Compare commits
9 Commits
dev-busine
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 89cc92cac5 | |||
| c8f640c6ef | |||
|
|
715b8abc5b | ||
| dbe236e821 | |||
| 923edea8bf | |||
| 6314ceb65a | |||
|
|
ad6b3f208c | ||
| cc069d0af1 | |||
| f353daccaa |
635
pages.json
@ -1,287 +1,348 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/home/home",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页",
|
||||
"navigationStyle": "custom",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/message",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "聊天",
|
||||
"enablePullDownRefresh": false,
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/mine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/contact",
|
||||
"style": {
|
||||
"navigationBarTitleText": "联系客服",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康柚",
|
||||
"navigationStyle": "custom",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/redirect-page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康柚",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康柚",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/common/privacy",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私政策",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/common/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户协议",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/web-view/web-view",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "pages/article",
|
||||
"name": "article",
|
||||
"pages": [
|
||||
{
|
||||
"path": "article-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的宣教",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "article-cate-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康宣教",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "article-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宣教文章",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "send-article",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择宣教文章",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/survey",
|
||||
"name": "survey",
|
||||
"pages": [
|
||||
{
|
||||
"path": "survey-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的问卷",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "fill",
|
||||
"style": {
|
||||
"navigationBarTitleText": "问卷",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/rate",
|
||||
"name": "rate",
|
||||
"pages": [
|
||||
{
|
||||
"path": "rate-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务评价",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "rate-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务评价",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/archive",
|
||||
"name": "archive",
|
||||
"pages": [
|
||||
{
|
||||
"path": "archive-manage",
|
||||
"style": {
|
||||
"navigationBarTitleText": "档案管理",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "edit-archive",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增档案",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "archive-result",
|
||||
"style": {
|
||||
"navigationBarTitleText": "团队服务",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health",
|
||||
"name": "health",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康信息",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康信息",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/library",
|
||||
"name": "library",
|
||||
"pages": [
|
||||
{
|
||||
"path": "diagnosis-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择诊断",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/team",
|
||||
"name": "team",
|
||||
"pages": [
|
||||
{
|
||||
"path": "team-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "团队介绍",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "homepage",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人主页",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "friend",
|
||||
"style": {
|
||||
"navigationBarTitleText": "添加好友",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "business-card",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人名片",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#065bd6",
|
||||
"backgroundColor": "#065bd6"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#666666",
|
||||
"selectedColor": "#007aff",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "white",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/home",
|
||||
"iconPath": "static/tabbar/home.png",
|
||||
"selectedIconPath": "static/tabbar/home_selected.png",
|
||||
"text": "服务"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/message/message",
|
||||
"iconPath": "static/tabbar/consult.png",
|
||||
"selectedIconPath": "static/tabbar/consult_selected.png",
|
||||
"text": "咨询"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/mine",
|
||||
"iconPath": "static/tabbar/mine.png",
|
||||
"selectedIconPath": "static/tabbar/mine_selected.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
}
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/home/home",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页",
|
||||
"navigationStyle": "custom",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/message",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/message/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "聊天",
|
||||
"enablePullDownRefresh": false,
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/mine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine/contact",
|
||||
"style": {
|
||||
"navigationBarTitleText": "联系客服",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康柚",
|
||||
"navigationStyle": "custom",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/redirect-page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康柚",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康柚",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/common/privacy",
|
||||
"style": {
|
||||
"navigationBarTitleText": "隐私政策",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/common/agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户协议",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/web-view/web-view",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
{
|
||||
"root": "pages/article",
|
||||
"name": "article",
|
||||
"pages": [
|
||||
{
|
||||
"path": "article-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的宣教",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "article-cate-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康宣教",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "article-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "宣教文章",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "send-article",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择宣教文章",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/survey",
|
||||
"name": "survey",
|
||||
"pages": [
|
||||
{
|
||||
"path": "survey-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的问卷",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "fill",
|
||||
"style": {
|
||||
"navigationBarTitleText": "问卷",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/rate",
|
||||
"name": "rate",
|
||||
"pages": [
|
||||
{
|
||||
"path": "rate-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务评价",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "rate-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务评价",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/experience-coupon",
|
||||
"name": "experience-coupon",
|
||||
"pages": [
|
||||
{
|
||||
"path": "claim",
|
||||
"style": {
|
||||
"navigationBarTitleText": "领取体验券",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my-rights",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的权益",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "select-rights-archive",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择档案",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my-coupons",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的体验券",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "wallet",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的卡包",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/record",
|
||||
"name": "record",
|
||||
"pages": [
|
||||
{
|
||||
"path": "treatment-record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "治疗记录",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "appointment-record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "预约记录",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/archive",
|
||||
"name": "archive",
|
||||
"pages": [
|
||||
{
|
||||
"path": "archive-manage",
|
||||
"style": {
|
||||
"navigationBarTitleText": "档案管理",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "edit-archive",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增档案",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "archive-result",
|
||||
"style": {
|
||||
"navigationBarTitleText": "团队服务",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health",
|
||||
"name": "health",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康信息",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康信息",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/library",
|
||||
"name": "library",
|
||||
"pages": [
|
||||
{
|
||||
"path": "diagnosis-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择诊断",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/team",
|
||||
"name": "team",
|
||||
"pages": [
|
||||
{
|
||||
"path": "team-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "团队介绍",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "homepage",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人主页",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "friend",
|
||||
"style": {
|
||||
"navigationBarTitleText": "添加好友",
|
||||
"disableScroll": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "business-card",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人名片",
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "uni-app",
|
||||
"navigationBarBackgroundColor": "#065bd6",
|
||||
"backgroundColor": "#065bd6"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#666666",
|
||||
"selectedColor": "#007aff",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "white",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/home",
|
||||
"iconPath": "static/tabbar/home.png",
|
||||
"selectedIconPath": "static/tabbar/home_selected.png",
|
||||
"text": "服务"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/message/message",
|
||||
"iconPath": "static/tabbar/consult.png",
|
||||
"selectedIconPath": "static/tabbar/consult_selected.png",
|
||||
"text": "咨询"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/mine",
|
||||
"iconPath": "static/tabbar/mine.png",
|
||||
"selectedIconPath": "static/tabbar/mine_selected.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"uniIdRouter": {}
|
||||
}
|
||||
|
||||
301
pages/experience-coupon/claim.vue
Normal file
@ -0,0 +1,301 @@
|
||||
<template>
|
||||
<full-page>
|
||||
<view class="claim-page">
|
||||
<view v-if="tip" class="tip">{{ tip }}</view>
|
||||
<view v-else class="tip">加载中...</view>
|
||||
</view>
|
||||
|
||||
<view v-if="posterVisible" class="poster-mask">
|
||||
<view class="poster-dialog">
|
||||
<image class="poster-image" :src="issue?.posterUrl || ''" mode="widthFix" />
|
||||
<view class="poster-content">{{ buildClaimContent() }}</view>
|
||||
<view class="poster-btn" :class="{ disabled: claiming }" @click="acceptCoupon">
|
||||
{{ claiming ? "领取中..." : "接受" }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</full-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, ref } from "vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||
import useAccount from "@/store/account";
|
||||
import api from "@/utils/api";
|
||||
import { confirm, hideLoading, loading, toast } from "@/utils/widget";
|
||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||
import FullPage from "@/components/full-page.vue";
|
||||
|
||||
const { account } = storeToRefs(useAccount());
|
||||
const { login } = useAccount();
|
||||
|
||||
const corpId = ref("");
|
||||
const issueId = ref("");
|
||||
const memberId = ref("");
|
||||
const issue = ref(null);
|
||||
const tip = ref("");
|
||||
const claiming = ref(false);
|
||||
const autoPrompted = ref(false);
|
||||
const posterVisible = ref(false);
|
||||
|
||||
const projectNameText = computed(() => {
|
||||
const projects = Array.isArray(issue.value?.projectSnapshot) ? issue.value.projectSnapshot : [];
|
||||
if (!projects.length) return "未配置项目";
|
||||
return projects.map((p) => p.projectName || "项目").join("、");
|
||||
});
|
||||
|
||||
function buildClaimContent() {
|
||||
const name = issue.value?.activityName || "体验券";
|
||||
return `您收到一张【${name}】体验券,包含${projectNameText.value},是否存入您的权益卡包?`;
|
||||
}
|
||||
|
||||
async function ensureLogin() {
|
||||
if (!account.value) await login();
|
||||
if (!account.value) {
|
||||
tip.value = "请先登录后再领取体验券";
|
||||
uni.navigateTo({ url: "/pages/login/login" });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function loadIssueDetail() {
|
||||
const res = await api(
|
||||
"getExperienceCouponIssueDetail",
|
||||
{ corpId: corpId.value, issueId: issueId.value },
|
||||
false
|
||||
);
|
||||
if (!res?.success || !res.data) {
|
||||
tip.value = res?.message || "体验券不存在或已失效";
|
||||
return false;
|
||||
}
|
||||
issue.value = res.data;
|
||||
if (!memberId.value && res.data.customerId) {
|
||||
memberId.value = res.data.customerId;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function hasBoundArchive() {
|
||||
const openid = account.value?.openid || "";
|
||||
if (!openid || !corpId.value) return false;
|
||||
|
||||
if (memberId.value) {
|
||||
try {
|
||||
const detail = await api(
|
||||
"getCustomerByCustomerId",
|
||||
{ corpId: corpId.value, customerId: memberId.value },
|
||||
false
|
||||
);
|
||||
const customer = detail?.data || null;
|
||||
if (customer && String(customer.miniAppId || "") === String(openid)) {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("getCustomerByCustomerId failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const countRes = await api(
|
||||
"getWxAppCustomerCount",
|
||||
{ miniAppId: openid, corpId: corpId.value },
|
||||
false
|
||||
);
|
||||
return Number(countRes?.data || 0) > 0;
|
||||
} catch (e) {
|
||||
console.warn("getWxAppCustomerCount failed", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function goBindArchive() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/archive/archive-manage?corpId=${encodeURIComponent(corpId.value || "")}`,
|
||||
});
|
||||
}
|
||||
|
||||
function isExpiredIssue() {
|
||||
const expireAt = Number(issue.value?.projectExpireTime || 0);
|
||||
if (expireAt && Date.now() > expireAt) return true;
|
||||
const rule = issue.value?.projectValidRuleSnapshot || {};
|
||||
if (rule.type === "fixedDate" && rule.fixedDate && Date.now() > Number(rule.fixedDate)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function acceptCoupon() {
|
||||
if (claiming.value || !issue.value) return;
|
||||
|
||||
claiming.value = true;
|
||||
loading("领取中...");
|
||||
try {
|
||||
const res = await api("claimExperienceCoupon", {
|
||||
corpId: corpId.value,
|
||||
issueId: issueId.value,
|
||||
claimUserId: account.value?.openid || "",
|
||||
});
|
||||
hideLoading();
|
||||
if (!res?.success) {
|
||||
tip.value = res?.message || "领取失败";
|
||||
toast(tip.value);
|
||||
return;
|
||||
}
|
||||
toast("领取成功");
|
||||
posterVisible.value = false;
|
||||
uni.redirectTo({
|
||||
url: `/pages/experience-coupon/my-rights?corpId=${encodeURIComponent(corpId.value)}&customerId=${encodeURIComponent(memberId.value || "")}&name=${encodeURIComponent(issue.value.customerName || "")}`,
|
||||
});
|
||||
} catch (e) {
|
||||
hideLoading();
|
||||
tip.value = e?.message || "领取失败";
|
||||
toast(tip.value);
|
||||
} finally {
|
||||
claiming.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function promptClaim() {
|
||||
if (autoPrompted.value) return;
|
||||
autoPrompted.value = true;
|
||||
|
||||
if (!issue.value) return;
|
||||
if (issue.value.status === "claimed") {
|
||||
tip.value = "该体验券已领取";
|
||||
uni.redirectTo({
|
||||
url: `/pages/experience-coupon/my-rights?corpId=${encodeURIComponent(corpId.value)}&customerId=${encodeURIComponent(memberId.value || "")}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (issue.value.status === "void") {
|
||||
tip.value = "该体验券已作废";
|
||||
return;
|
||||
}
|
||||
if (issue.value.status && issue.value.status !== "issued") {
|
||||
tip.value = "当前状态不可领取";
|
||||
return;
|
||||
}
|
||||
if (isExpiredIssue()) {
|
||||
tip.value = "体验券已过期,无法领取";
|
||||
return;
|
||||
}
|
||||
|
||||
const bound = await hasBoundArchive();
|
||||
if (!bound) {
|
||||
tip.value = "请先绑定档案后再领取体验券";
|
||||
try {
|
||||
await confirm("请先绑定档案后再领取体验券", {
|
||||
title: "提示",
|
||||
confirmText: "去绑定",
|
||||
cancelText: "取消",
|
||||
});
|
||||
goBindArchive();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tip.value = "";
|
||||
posterVisible.value = true;
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
loading("加载中...");
|
||||
try {
|
||||
const okLogin = await ensureLogin();
|
||||
if (!okLogin) return;
|
||||
const okDetail = await loadIssueDetail();
|
||||
if (!okDetail) return;
|
||||
await promptClaim();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
onLoad((options = {}) => {
|
||||
corpId.value = normalizeCorpId(options.corpId || "");
|
||||
issueId.value = options.issueId || options.id || "";
|
||||
memberId.value = options.memberId || options.customerId || "";
|
||||
if (!corpId.value || !issueId.value) {
|
||||
tip.value = "领取参数不完整";
|
||||
toast(tip.value);
|
||||
return;
|
||||
}
|
||||
bootstrap();
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
if (issue.value && issue.value.status === "issued" && tip.value.includes("绑定")) {
|
||||
autoPrompted.value = false;
|
||||
promptClaim();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.claim-page {
|
||||
min-height: 100%;
|
||||
padding: 30rpx;
|
||||
box-sizing: border-box;
|
||||
background: #f6fafa;
|
||||
}
|
||||
|
||||
.tip {
|
||||
margin-top: 120rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
.poster-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx;
|
||||
box-sizing: border-box;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.poster-dialog {
|
||||
width: 100%;
|
||||
max-width: 620rpx;
|
||||
overflow: hidden;
|
||||
border-radius: 20rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.poster-image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-height: 700rpx;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.poster-content {
|
||||
padding: 28rpx 30rpx 8rpx;
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.poster-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 80rpx;
|
||||
margin: 24rpx 30rpx 30rpx;
|
||||
border-radius: 40rpx;
|
||||
background: #065bd6;
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.poster-btn.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
483
pages/experience-coupon/my-coupons.vue
Normal file
@ -0,0 +1,483 @@
|
||||
<template>
|
||||
<full-page pageClass="coupons-page" :customScroll="true">
|
||||
<scroll-view
|
||||
class="coupon-scroll"
|
||||
scroll-y="true"
|
||||
refresher-enabled="true"
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="refreshCoupons"
|
||||
>
|
||||
<view class="page-body">
|
||||
<view v-if="loading" class="empty">加载中...</view>
|
||||
<view v-else-if="!list.length" class="empty">暂无待领取体验券</view>
|
||||
<view v-else class="coupon-list">
|
||||
<view
|
||||
v-for="item in list"
|
||||
:key="item._id"
|
||||
class="coupon-card"
|
||||
@click="openPoster(item)"
|
||||
>
|
||||
<image
|
||||
v-if="item.posterUrl"
|
||||
class="coupon-poster"
|
||||
:src="item.posterUrl"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view v-else class="coupon-poster coupon-poster--empty">体验券</view>
|
||||
<view class="coupon-body">
|
||||
<view class="coupon-title">{{ item.activityName || "体验券" }}</view>
|
||||
<view class="coupon-info-grid">
|
||||
<view class="coupon-info-row coupon-info-row--projects">
|
||||
<text class="coupon-info-label">项目</text>
|
||||
<view class="coupon-project-list">
|
||||
<view
|
||||
v-for="project in item.projectSnapshot || []"
|
||||
:key="project.projectId"
|
||||
class="coupon-project-item"
|
||||
>
|
||||
<text>{{ project.projectName || "未命名项目" }}</text>
|
||||
<text>×{{ project.usageCount || 1 }}</text>
|
||||
</view>
|
||||
<text v-if="!(item.projectSnapshot || []).length">未配置项目</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="coupon-info-row">
|
||||
<text class="coupon-info-label">项目有效期</text>
|
||||
<text>{{ item.validText }}</text>
|
||||
</view>
|
||||
<view class="coupon-info-row">
|
||||
<text class="coupon-info-label">活动有效期</text>
|
||||
<text>{{ item.activityValidText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="coupon-action">点击查看海报领取</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 海报领取弹窗 -->
|
||||
<view v-if="posterVisible" class="poster-mask" @click="closePoster">
|
||||
<view class="poster-dialog" @click.stop>
|
||||
<image
|
||||
class="poster-image"
|
||||
:src="current?.posterUrl || ''"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<view class="poster-info">
|
||||
<view class="poster-title">{{ current?.activityName || "体验券" }}</view>
|
||||
<view class="poster-desc">{{ current?.projectText }}</view>
|
||||
</view>
|
||||
<view class="poster-btn" :class="{ disabled: claiming }" @click="acceptCoupon">
|
||||
{{ claiming ? "领取中..." : "接受" }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</full-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { 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 } 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 { account } = storeToRefs(useAccount());
|
||||
const { getTeams } = useAccount();
|
||||
|
||||
const corpId = ref("");
|
||||
const teamId = ref("");
|
||||
const customerId = ref("");
|
||||
const list = ref([]);
|
||||
const loading = ref(false);
|
||||
const refreshing = ref(false);
|
||||
const posterVisible = ref(false);
|
||||
const current = ref(null);
|
||||
const claiming = 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 projectText(projects) {
|
||||
const arr = Array.isArray(projects) ? projects : [];
|
||||
if (!arr.length) return "未配置项目";
|
||||
return arr.map((p) => `${p.projectName || "项目"}×${p.usageCount || 1}`).join("、");
|
||||
}
|
||||
|
||||
function buildValidText(item) {
|
||||
const rule = item.projectValidRuleSnapshot || {};
|
||||
if (item.projectExpireTime) return `有效期至 ${formatDate(item.projectExpireTime)}`;
|
||||
if (rule.type === "fixedDate" && rule.fixedDate) {
|
||||
return `有效期至 ${formatDate(rule.fixedDate)}`;
|
||||
}
|
||||
if (rule.type === "daysAfterClaim") {
|
||||
return `领取后 ${rule.days || 0} 天有效`;
|
||||
}
|
||||
return "领取后按活动规则生效";
|
||||
}
|
||||
|
||||
function buildActivityValidText(item) {
|
||||
const start = formatDate(item.activityStartTime) || "-";
|
||||
const end = formatDate(item.activityEndTime) || "-";
|
||||
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) {
|
||||
const expireAt = getExpireAt(item);
|
||||
if (!expireAt) return false;
|
||||
return Date.now() > expireAt;
|
||||
}
|
||||
|
||||
async function resolveContext(options = {}) {
|
||||
corpId.value = normalizeCorpId(options.corpId || corpId.value || "");
|
||||
teamId.value = options.teamId || teamId.value || "";
|
||||
customerId.value = options.customerId || options.memberId || customerId.value || "";
|
||||
|
||||
const cached = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
|
||||
let teams = [];
|
||||
try {
|
||||
teams = (await getTeams()) || [];
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
const matched =
|
||||
teams.find((t) => t.teamId === (teamId.value || cached.teamId)) ||
|
||||
teams.find((t) => normalizeCorpId(t.corpId) === corpId.value) ||
|
||||
teams[0] ||
|
||||
null;
|
||||
|
||||
if (!corpId.value) corpId.value = normalizeCorpId(matched?.corpId || cached.corpId || "");
|
||||
if (!teamId.value) teamId.value = matched?.teamId || cached.teamId || "";
|
||||
if (!corpId.value) return false;
|
||||
|
||||
if (customerId.value) return true;
|
||||
|
||||
const miniAppId = account.value?.openid || uni.getStorageSync("openid") || "";
|
||||
if (!miniAppId) 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((c) => c.relationship === "本人") || customers[0];
|
||||
customerId.value = preferred?._id || "";
|
||||
return !!customerId.value;
|
||||
}
|
||||
|
||||
async function voidExpired(item) {
|
||||
try {
|
||||
await api(
|
||||
"voidExperienceCouponIssue",
|
||||
{
|
||||
corpId: corpId.value,
|
||||
issueId: item._id,
|
||||
voidReason: "有效期内未领取,自动失效",
|
||||
},
|
||||
false
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn("auto void failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCoupons(options = {}) {
|
||||
const { silent = false } = options;
|
||||
if (!corpId.value || !customerId.value) {
|
||||
list.value = [];
|
||||
return;
|
||||
}
|
||||
if (!silent) loading.value = true;
|
||||
try {
|
||||
const res = await api(
|
||||
"getCustomerExperienceCoupons",
|
||||
{
|
||||
corpId: corpId.value,
|
||||
customerId: customerId.value,
|
||||
status: "issued",
|
||||
page: 1,
|
||||
pageSize: 100,
|
||||
},
|
||||
false
|
||||
);
|
||||
if (!res?.success) {
|
||||
toast(res?.message || "加载体验券失败");
|
||||
list.value = [];
|
||||
return;
|
||||
}
|
||||
const raw = res.list || res.data?.list || [];
|
||||
const valid = [];
|
||||
for (const item of raw) {
|
||||
if (isExpired(item)) {
|
||||
voidExpired(item);
|
||||
continue;
|
||||
}
|
||||
valid.push({
|
||||
...item,
|
||||
projectText: projectText(item.projectSnapshot),
|
||||
validText: buildValidText(item),
|
||||
activityValidText: buildActivityValidText(item),
|
||||
});
|
||||
}
|
||||
list.value = valid;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshCoupons() {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await loadCoupons({ silent: true });
|
||||
} finally {
|
||||
refreshing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function openPoster(item) {
|
||||
if (!item?.posterUrl) {
|
||||
toast("该体验券暂无海报");
|
||||
return;
|
||||
}
|
||||
current.value = item;
|
||||
posterVisible.value = true;
|
||||
}
|
||||
|
||||
function closePoster() {
|
||||
if (claiming.value) return;
|
||||
posterVisible.value = false;
|
||||
current.value = null;
|
||||
}
|
||||
|
||||
async function acceptCoupon() {
|
||||
if (!current.value || claiming.value) return;
|
||||
claiming.value = true;
|
||||
try {
|
||||
const res = await api("claimExperienceCoupon", {
|
||||
corpId: corpId.value,
|
||||
issueId: current.value._id,
|
||||
claimUserId: account.value?.openid || "",
|
||||
});
|
||||
if (!res?.success) {
|
||||
toast(res?.message || "领取失败");
|
||||
return;
|
||||
}
|
||||
toast("领取成功");
|
||||
posterVisible.value = false;
|
||||
uni.redirectTo({
|
||||
url: `/pages/experience-coupon/my-rights?corpId=${encodeURIComponent(corpId.value)}&teamId=${encodeURIComponent(teamId.value)}&customerId=${encodeURIComponent(customerId.value)}&name=${encodeURIComponent(current.value.customerName || "")}`,
|
||||
});
|
||||
} catch (e) {
|
||||
toast(e?.message || "领取失败");
|
||||
} finally {
|
||||
claiming.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onLoad(async (options = {}) => {
|
||||
uni.setNavigationBarTitle({ title: "我的体验券" });
|
||||
const ok = await resolveContext(options);
|
||||
if (!ok) {
|
||||
toast("请先绑定档案");
|
||||
return;
|
||||
}
|
||||
await loadCoupons();
|
||||
});
|
||||
|
||||
onShow(async () => {
|
||||
if (corpId.value && customerId.value) {
|
||||
await loadCoupons();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.coupons-page :deep(.page-scroll) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.coupon-scroll {
|
||||
height: 100%;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.page-body {
|
||||
min-height: 100%;
|
||||
padding: 24rpx 30rpx 40rpx;
|
||||
box-sizing: border-box;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.coupon-card {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 8rpx 10rpx 0 rgba(60, 169, 145, 0.06);
|
||||
}
|
||||
|
||||
.coupon-poster {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #f5f7fa;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.coupon-poster--empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #c0c4cc;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.coupon-body {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.coupon-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.coupon-info-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6rpx;
|
||||
color: #606266;
|
||||
font-size: 22rpx;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.coupon-info-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.coupon-info-label {
|
||||
width: 132rpx;
|
||||
flex-shrink: 0;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.coupon-info-row > text:last-child,
|
||||
.coupon-project-list {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.coupon-project-list {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.coupon-project-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.coupon-project-item text:first-child {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.coupon-action {
|
||||
margin-top: 12rpx;
|
||||
font-size: 22rpx;
|
||||
color: #ff8a00;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 120rpx 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.poster-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(0, 0, 0, 0.65);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.poster-dialog {
|
||||
width: 100%;
|
||||
max-width: 620rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.poster-image {
|
||||
width: 100%;
|
||||
display: block;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.poster-info {
|
||||
padding: 24rpx 28rpx 8rpx;
|
||||
}
|
||||
|
||||
.poster-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #222;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.poster-desc {
|
||||
font-size: 24rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.poster-btn {
|
||||
margin: 24rpx 28rpx 32rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: #065bd6;
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.poster-btn.disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
</style>
|
||||
441
pages/experience-coupon/my-rights.vue
Normal file
@ -0,0 +1,441 @@
|
||||
<template>
|
||||
<full-page pageClass="rights-page" :customScroll="true">
|
||||
<scroll-view
|
||||
class="rights-scroll"
|
||||
scroll-y="true"
|
||||
refresher-enabled="true"
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="refreshRights"
|
||||
>
|
||||
<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>
|
||||
</scroll-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);
|
||||
const refreshing = 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(options = {}) {
|
||||
const { silent = false } = options;
|
||||
if (!corpId.value || !customerId.value) {
|
||||
records.value = [];
|
||||
return;
|
||||
}
|
||||
if (!silent) 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 refreshRights() {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await loadRights({ silent: true });
|
||||
} finally {
|
||||
refreshing.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>
|
||||
.rights-page :deep(.page-scroll) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.rights-scroll {
|
||||
height: 100%;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.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>
|
||||
293
pages/experience-coupon/select-rights-archive.vue
Normal file
@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<full-page pageClass="rights-selector-page" :customScroll="true">
|
||||
<view class="page-body">
|
||||
<view v-if="loading" class="empty">加载中...</view>
|
||||
<view v-else-if="!options.length" class="empty">暂无可用档案</view>
|
||||
<view v-else class="archive-list">
|
||||
<view
|
||||
v-for="item in options"
|
||||
:key="item.key"
|
||||
class="archive-card"
|
||||
:class="{ active: item.isCurrent }"
|
||||
@click="selectArchive(item)"
|
||||
>
|
||||
<view class="archive-head">
|
||||
<view class="archive-name-row">
|
||||
<view class="archive-name">{{ item.name || "未命名" }}</view>
|
||||
<view v-if="item.relationship" class="archive-tag">{{ item.relationship }}</view>
|
||||
</view>
|
||||
<view v-if="item.isCurrent" class="archive-current">当前</view>
|
||||
</view>
|
||||
<view class="archive-meta">{{ item.metaText }}</view>
|
||||
<view class="archive-id">证件号:{{ item.idCardText }}</view>
|
||||
<view class="archive-corp">{{ item.corpName }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</full-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { storeToRefs } from "pinia";
|
||||
import useAccount from "@/store/account";
|
||||
import api from "@/utils/api";
|
||||
import { set } from "@/utils/cache";
|
||||
import { toast } from "@/utils/widget";
|
||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||
import FullPage from "@/components/full-page.vue";
|
||||
|
||||
const RIGHTS_SELECTION_CACHE_KEY = "experience-coupon-rights-selection";
|
||||
const { account } = storeToRefs(useAccount());
|
||||
const { getTeams } = useAccount();
|
||||
|
||||
const loading = ref(false);
|
||||
const options = ref([]);
|
||||
const currentCorpId = ref("");
|
||||
const currentTeamId = ref("");
|
||||
const currentCustomerId = ref("");
|
||||
const mode = ref("back");
|
||||
const target = ref("");
|
||||
|
||||
function pickCorpName(team = {}) {
|
||||
return team.licenseHospitalName || team.leaderCorp || team.corpName || "-";
|
||||
}
|
||||
|
||||
function maskMobile(mobile = "") {
|
||||
const value = String(mobile || "").trim();
|
||||
if (!value) return "";
|
||||
if (/^\d{11}$/.test(value)) {
|
||||
return value.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function maskIdCard(idCard = "") {
|
||||
const value = String(idCard || "").trim();
|
||||
if (!value) return "--";
|
||||
if (value.length <= 4) return value;
|
||||
return `${"*".repeat(Math.max(value.length - 4, 2))}${value.slice(-4)}`;
|
||||
}
|
||||
|
||||
function buildMetaText(customer = {}) {
|
||||
const parts = [];
|
||||
if (customer.age) parts.push(`${customer.age}岁`);
|
||||
if (customer.mobile) parts.push(maskMobile(customer.mobile));
|
||||
return parts.length ? parts.join(",") : "暂无档案信息";
|
||||
}
|
||||
|
||||
function dedupeByCorp(list = []) {
|
||||
const map = new Map();
|
||||
list.forEach((team) => {
|
||||
const corpId = normalizeCorpId(team.corpId);
|
||||
if (!corpId || map.has(corpId)) return;
|
||||
map.set(corpId, { ...team, corpId });
|
||||
});
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
function buildTargetUrl(item) {
|
||||
const corp = encodeURIComponent(item.corpId || "");
|
||||
const team = encodeURIComponent(item.teamId || "");
|
||||
const customer = encodeURIComponent(item.customerId || "");
|
||||
const name = encodeURIComponent(item.name || "");
|
||||
|
||||
if (target.value === "coupons") {
|
||||
return `/pages/experience-coupon/my-coupons?corpId=${corp}&teamId=${team}&customerId=${customer}`;
|
||||
}
|
||||
if (target.value === "health") {
|
||||
return `/pages/health/list?teamId=${team}&corpId=${corp}&id=${customer}&name=${name}`;
|
||||
}
|
||||
if (target.value === "treatment") {
|
||||
const corpName = encodeURIComponent(item.corpName || "");
|
||||
return `/pages/record/treatment-record?teamId=${team}&corpId=${corp}&customerId=${customer}&name=${name}&corpName=${corpName}`;
|
||||
}
|
||||
if (target.value === "appointment") {
|
||||
const corpName = encodeURIComponent(item.corpName || "");
|
||||
return `/pages/record/appointment-record?teamId=${team}&corpId=${corp}&customerId=${customer}&name=${name}&corpName=${corpName}`;
|
||||
}
|
||||
return `/pages/experience-coupon/my-rights?corpId=${corp}&teamId=${team}&customerId=${customer}&name=${name}`;
|
||||
}
|
||||
|
||||
async function loadArchives() {
|
||||
const miniAppId = account.value?.openid || uni.getStorageSync("openid") || "";
|
||||
if (!miniAppId) {
|
||||
options.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const teams = (await getTeams()) || [];
|
||||
const corpTeams = dedupeByCorp(teams);
|
||||
const responses = await Promise.all(
|
||||
corpTeams.map(async (team) => {
|
||||
try {
|
||||
const res = await api("getMiniAppCustomers", { miniAppId, corpId: team.corpId }, false);
|
||||
const customers = res?.success && Array.isArray(res.data) ? res.data : [];
|
||||
return customers.map((customer) => ({ team, customer }));
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
return [];
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const list = responses
|
||||
.flat()
|
||||
.map(({ team, customer }) => ({
|
||||
key: `${team.corpId}_${customer._id}`,
|
||||
corpId: team.corpId,
|
||||
teamId: team.teamId || "",
|
||||
customerId: customer._id || "",
|
||||
name: customer.name || "",
|
||||
relationship: customer.relationship || "",
|
||||
metaText: buildMetaText(customer),
|
||||
idCardText: maskIdCard(customer.idCard),
|
||||
corpName: pickCorpName(team),
|
||||
}))
|
||||
.filter((item) => item.corpId && item.customerId)
|
||||
.sort((a, b) => {
|
||||
const aScore =
|
||||
(a.corpId === currentCorpId.value ? 4 : 0) +
|
||||
(a.teamId === currentTeamId.value ? 2 : 0) +
|
||||
(a.customerId === currentCustomerId.value ? 8 : 0) +
|
||||
(a.relationship === "本人" ? 1 : 0);
|
||||
const bScore =
|
||||
(b.corpId === currentCorpId.value ? 4 : 0) +
|
||||
(b.teamId === currentTeamId.value ? 2 : 0) +
|
||||
(b.customerId === currentCustomerId.value ? 8 : 0) +
|
||||
(b.relationship === "本人" ? 1 : 0);
|
||||
return bScore - aScore;
|
||||
})
|
||||
.map((item) => ({
|
||||
...item,
|
||||
isCurrent:
|
||||
item.corpId === currentCorpId.value &&
|
||||
item.customerId === currentCustomerId.value,
|
||||
}));
|
||||
|
||||
options.value = list;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function selectArchive(item) {
|
||||
if (!item) return;
|
||||
|
||||
if (mode.value === "target") {
|
||||
uni.navigateTo({
|
||||
url: buildTargetUrl(item),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
set(RIGHTS_SELECTION_CACHE_KEY, {
|
||||
corpId: item.corpId,
|
||||
teamId: item.teamId,
|
||||
customerId: item.customerId,
|
||||
name: item.name,
|
||||
corpName: item.corpName,
|
||||
});
|
||||
uni.navigateBack();
|
||||
}
|
||||
|
||||
onLoad(async (optionsData = {}) => {
|
||||
uni.setNavigationBarTitle({ title: "选择档案" });
|
||||
currentCorpId.value = normalizeCorpId(optionsData.corpId || "");
|
||||
currentTeamId.value = optionsData.teamId || "";
|
||||
currentCustomerId.value = optionsData.customerId || optionsData.memberId || "";
|
||||
mode.value = optionsData.mode === "target" ? "target" : "back";
|
||||
target.value = optionsData.target || "rights";
|
||||
await loadArchives();
|
||||
if (!options.value.length) {
|
||||
toast("暂无可用档案");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-body {
|
||||
min-height: 100%;
|
||||
padding: 24rpx;
|
||||
box-sizing: border-box;
|
||||
background: #f5f6fa;
|
||||
}
|
||||
|
||||
.archive-card {
|
||||
background: #fff;
|
||||
border-radius: 18rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border: 2rpx solid transparent;
|
||||
box-shadow: 0 8rpx 24rpx rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
.archive-card.active {
|
||||
border-color: #065bd6;
|
||||
}
|
||||
|
||||
.archive-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.archive-name-row {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.archive-name {
|
||||
font-size: 34rpx;
|
||||
font-weight: 600;
|
||||
color: #1f2329;
|
||||
}
|
||||
|
||||
.archive-tag,
|
||||
.archive-current {
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 999rpx;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.archive-tag {
|
||||
color: #0f766e;
|
||||
background: rgba(15, 118, 110, 0.12);
|
||||
}
|
||||
|
||||
.archive-current {
|
||||
color: #065bd6;
|
||||
background: rgba(6, 91, 214, 0.1);
|
||||
}
|
||||
|
||||
.archive-meta,
|
||||
.archive-id {
|
||||
font-size: 28rpx;
|
||||
color: #4b5563;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.archive-corp {
|
||||
margin-top: 16rpx;
|
||||
padding-top: 16rpx;
|
||||
border-top: 1px solid #eef2f6;
|
||||
font-size: 28rpx;
|
||||
color: #065bd6;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding: 120rpx 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
36
pages/experience-coupon/wallet.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<view class="redirect-page">跳转中...</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
|
||||
onLoad((options = {}) => {
|
||||
const type = options.type === "coupon" ? "coupon" : "rights";
|
||||
const params = [
|
||||
options.corpId ? `corpId=${encodeURIComponent(options.corpId)}` : "",
|
||||
options.teamId ? `teamId=${encodeURIComponent(options.teamId)}` : "",
|
||||
options.customerId ? `customerId=${encodeURIComponent(options.customerId)}` : "",
|
||||
options.memberId ? `memberId=${encodeURIComponent(options.memberId)}` : "",
|
||||
options.name ? `name=${encodeURIComponent(options.name)}` : "",
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("&");
|
||||
|
||||
const target =
|
||||
type === "coupon"
|
||||
? `/pages/experience-coupon/my-coupons?${params}`
|
||||
: `/pages/experience-coupon/my-rights?${params}`;
|
||||
|
||||
uni.redirectTo({ url: target });
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.redirect-page {
|
||||
padding: 120rpx 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
@ -94,7 +94,7 @@ async function changeTeam({ teamId, corpId, corpUserId, externalUserId, qrid, re
|
||||
qrid,
|
||||
referenceCustomerId: referenceCustomerId || ''
|
||||
});
|
||||
await login()
|
||||
await login('', { forceVerify: true })
|
||||
if (account.value && account.value.mobile) {
|
||||
bindTeam({ corpUserId, externalUserId })
|
||||
} else {
|
||||
@ -147,6 +147,18 @@ onLoad((options) => {
|
||||
if (options.q) {
|
||||
opts.value = JSON.stringify(options)
|
||||
changeTeam(parseInviteOptions(options));
|
||||
} else if (options.type === 'experienceCoupon' && options.issueId && options.corpId) {
|
||||
const params = [
|
||||
`corpId=${encodeURIComponent(options.corpId || "")}`,
|
||||
`issueId=${encodeURIComponent(options.issueId || "")}`,
|
||||
options.memberId ? `memberId=${encodeURIComponent(options.memberId)}` : "",
|
||||
options.couponId ? `couponId=${encodeURIComponent(options.couponId)}` : "",
|
||||
options.unionid ? `unionid=${encodeURIComponent(options.unionid)}` : "",
|
||||
options.externalUserId ? `externalUserId=${encodeURIComponent(options.externalUserId)}` : "",
|
||||
].filter(Boolean).join("&");
|
||||
uni.redirectTo({
|
||||
url: `/pages/experience-coupon/claim?${params}`,
|
||||
});
|
||||
} else if (options.type === 'archive' || (options.teamId && options.corpId)) {
|
||||
changeTeam(options);
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<!-- Blue background area for header -->
|
||||
<view class="header-bg"></view>
|
||||
|
||||
<!-- User Card -->
|
||||
<view class="user-card">
|
||||
<view class="avatar-container">
|
||||
<uni-icons type="person-filled" size="60" color="#cccccc" class="default-avatar"></uni-icons>
|
||||
@ -14,7 +12,33 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Menu List -->
|
||||
<view class="shortcut-bar">
|
||||
<view class="shortcut-item" @click="openRightsWallet">
|
||||
<view class="shortcut-icon shortcut-icon--rights">
|
||||
<uni-icons type="gift" size="28" color="#065bd6"></uni-icons>
|
||||
</view>
|
||||
<text class="shortcut-title">我的权益</text>
|
||||
</view>
|
||||
<view class="shortcut-item" @click="openCouponWallet">
|
||||
<view class="shortcut-icon shortcut-icon--coupon">
|
||||
<uni-icons type="wallet" size="28" color="#ff8a00"></uni-icons>
|
||||
</view>
|
||||
<text class="shortcut-title">我的体验券</text>
|
||||
</view>
|
||||
<view class="shortcut-item" @click="openTreatmentRecord">
|
||||
<view class="shortcut-icon shortcut-icon--record">
|
||||
<uni-icons type="compose" size="28" color="#19be6b"></uni-icons>
|
||||
</view>
|
||||
<text class="shortcut-title">治疗记录</text>
|
||||
</view>
|
||||
<view class="shortcut-item" @click="openAppointmentRecord">
|
||||
<view class="shortcut-icon shortcut-icon--appointment">
|
||||
<uni-icons type="calendar" size="28" color="#7c3aed"></uni-icons>
|
||||
</view>
|
||||
<text class="shortcut-title">预约记录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="menu-container">
|
||||
<view class="px-15 py-12 flex items-center border-b" @click="toPage('/pages/mine/contact')">
|
||||
<view class="flex-shrink-0 item-icon">
|
||||
@ -53,81 +77,207 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="menu-container">
|
||||
<uni-list>
|
||||
<uni-list-item title="联系客服" link to="/pages/mine/contact" clickable>
|
||||
<template v-slot:header>
|
||||
<view class="item-icon">
|
||||
<uni-icons type="headphones" size="22" color="#000"></uni-icons>
|
||||
</view>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
<uni-list-item title="隐私保护政策" link to="/pages/common/privacy" clickable>
|
||||
<template v-slot:header>
|
||||
<view class="item-icon">
|
||||
<uni-icons type="locked" size="22" color="#000"></uni-icons>
|
||||
</view>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
<uni-list-item title="用户注册协议" link to="/pages/common/agreement" clickable>
|
||||
<template v-slot:header>
|
||||
<view class="item-icon">
|
||||
<uni-icons type="paperclip" size="22" color="#000"></uni-icons>
|
||||
</view>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
<uni-list-item title="退出登录" link @click="handleLogout">
|
||||
<template v-slot:header>
|
||||
<view class="item-icon">
|
||||
<uni-icons type="undo" size="22" color="#000"></uni-icons>
|
||||
</view>
|
||||
</template>
|
||||
</uni-list-item>
|
||||
</uni-list>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import { computed, ref } from "vue";
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import { storeToRefs } from "pinia";
|
||||
import accountStore from "@/store/account";
|
||||
import api from "@/utils/api";
|
||||
import { get } from "@/utils/cache";
|
||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||
import { toast } from "@/utils/widget";
|
||||
|
||||
const HOME_CURRENT_TEAM_CACHE_KEY = "home-current-team-info";
|
||||
|
||||
const store = accountStore();
|
||||
const { account } = storeToRefs(store);
|
||||
const { getTeams, login } = store;
|
||||
|
||||
const context = ref({
|
||||
corpId: "",
|
||||
teamId: "",
|
||||
customerId: "",
|
||||
customerName: "",
|
||||
customers: [],
|
||||
});
|
||||
const resolving = ref(false);
|
||||
|
||||
const maskedPhone = computed(() => {
|
||||
const account = uni.getStorageSync('account');
|
||||
const mobile = account?.mobile || store.account?.mobile || '';
|
||||
if (!mobile) return '';
|
||||
return mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
|
||||
const localAccount = uni.getStorageSync("account");
|
||||
const mobile = localAccount?.mobile || account.value?.mobile || "";
|
||||
if (!mobile) return "";
|
||||
return mobile.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
|
||||
});
|
||||
|
||||
const handleLogout = () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
title: "提示",
|
||||
content: "确定要退出登录吗?",
|
||||
success: function (res) {
|
||||
if (res.confirm) {
|
||||
// Clear login info
|
||||
uni.removeStorageSync('account');
|
||||
uni.removeStorageSync('openid');
|
||||
uni.removeStorageSync("account");
|
||||
uni.removeStorageSync("openid");
|
||||
store.account = null;
|
||||
|
||||
// Redirect to login or home
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
url: "/pages/login/login",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
function toPage(url) {
|
||||
function pickPreferredCustomer(list = []) {
|
||||
if (!Array.isArray(list) || !list.length) return null;
|
||||
return list.find((item) => item.relationship === "本人") || list[0] || null;
|
||||
}
|
||||
|
||||
async function ensureLogin() {
|
||||
if (account.value?.openid) return true;
|
||||
const local = uni.getStorageSync("account");
|
||||
if (local?.openid) {
|
||||
store.account = local;
|
||||
return true;
|
||||
}
|
||||
const res = await login();
|
||||
return !!(res && res.openid);
|
||||
}
|
||||
|
||||
async function resolveTeam() {
|
||||
const cached = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
|
||||
let teams = [];
|
||||
try {
|
||||
teams = (await getTeams()) || [];
|
||||
} catch (e) {
|
||||
console.warn("getTeams failed", e);
|
||||
}
|
||||
const cachedCorpId = normalizeCorpId(cached.corpId || "");
|
||||
const matched =
|
||||
teams.find(
|
||||
(item) =>
|
||||
item.teamId === cached.teamId &&
|
||||
(!cachedCorpId || normalizeCorpId(item.corpId || "") === cachedCorpId)
|
||||
) ||
|
||||
teams.find((item) => item.teamId === cached.teamId) ||
|
||||
teams[0] ||
|
||||
null;
|
||||
|
||||
return {
|
||||
corpId: normalizeCorpId(matched?.corpId || cached.corpId || ""),
|
||||
teamId: matched?.teamId || cached.teamId || "",
|
||||
};
|
||||
}
|
||||
|
||||
async function resolveContext({ force = false } = {}) {
|
||||
if (resolving.value) return context.value;
|
||||
if (!force && context.value.corpId && context.value.customerId) {
|
||||
return context.value;
|
||||
}
|
||||
|
||||
resolving.value = true;
|
||||
try {
|
||||
const ok = await ensureLogin();
|
||||
if (!ok) {
|
||||
toast("请先登录");
|
||||
return null;
|
||||
}
|
||||
|
||||
const team = await resolveTeam();
|
||||
if (!team.corpId) {
|
||||
toast("请先加入服务团队");
|
||||
return null;
|
||||
}
|
||||
|
||||
const miniAppId = account.value?.openid || uni.getStorageSync("openid") || "";
|
||||
const res = await api(
|
||||
"getMiniAppCustomers",
|
||||
{ miniAppId, corpId: team.corpId },
|
||||
false
|
||||
);
|
||||
const customers = res?.success && Array.isArray(res.data) ? res.data : [];
|
||||
const preferred = pickPreferredCustomer(customers);
|
||||
|
||||
context.value = {
|
||||
corpId: team.corpId,
|
||||
teamId: team.teamId,
|
||||
customerId: preferred?._id || "",
|
||||
customerName: preferred
|
||||
? `${preferred.name || ""}${preferred.relationship ? ` ${preferred.relationship}` : ""}`.trim()
|
||||
: "",
|
||||
customers,
|
||||
};
|
||||
return context.value;
|
||||
} finally {
|
||||
resolving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function goBindArchive(ctx) {
|
||||
const corpId = ctx?.corpId || "";
|
||||
const teamId = ctx?.teamId || "";
|
||||
uni.navigateTo({
|
||||
url: url
|
||||
url: `/pages/archive/archive-manage?corpId=${encodeURIComponent(corpId)}&teamId=${encodeURIComponent(teamId)}`,
|
||||
});
|
||||
}
|
||||
|
||||
function openArchiveSelector(target, ctx) {
|
||||
const params = [
|
||||
`mode=target`,
|
||||
`target=${encodeURIComponent(target)}`,
|
||||
`corpId=${encodeURIComponent(ctx?.corpId || "")}`,
|
||||
`teamId=${encodeURIComponent(ctx?.teamId || "")}`,
|
||||
`customerId=${encodeURIComponent(ctx?.customerId || "")}`,
|
||||
`name=${encodeURIComponent(ctx?.customerName || "")}`,
|
||||
].join("&");
|
||||
uni.navigateTo({
|
||||
url: `/pages/experience-coupon/select-rights-archive?${params}`,
|
||||
});
|
||||
}
|
||||
|
||||
async function openWithArchive(target) {
|
||||
const ctx = await resolveContext({ force: true });
|
||||
if (!ctx) return;
|
||||
|
||||
if (!ctx.customerId) {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "请先绑定档案后再查看",
|
||||
confirmText: "去绑定",
|
||||
success: (res) => {
|
||||
if (res.confirm) goBindArchive(ctx);
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
openArchiveSelector(target, ctx);
|
||||
}
|
||||
|
||||
async function openRightsWallet() {
|
||||
await openWithArchive("rights");
|
||||
}
|
||||
|
||||
async function openCouponWallet() {
|
||||
await openWithArchive("coupons");
|
||||
}
|
||||
|
||||
async function openTreatmentRecord() {
|
||||
await openWithArchive("treatment");
|
||||
}
|
||||
|
||||
async function openAppointmentRecord() {
|
||||
await openWithArchive("appointment");
|
||||
}
|
||||
|
||||
function toPage(url) {
|
||||
uni.navigateTo({ url });
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
resolveContext({ force: true });
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@ -184,14 +334,67 @@ page {
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-bar {
|
||||
margin: 0 15px 15px;
|
||||
padding: 12px 0 10px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.shortcut-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.shortcut-icon {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.shortcut-icon--rights {
|
||||
background: #eef5ff;
|
||||
}
|
||||
|
||||
.shortcut-icon--coupon {
|
||||
background: #fff6e8;
|
||||
}
|
||||
|
||||
.shortcut-icon--record {
|
||||
background: #ecfff5;
|
||||
}
|
||||
|
||||
.shortcut-icon--appointment {
|
||||
background: #f3edff;
|
||||
}
|
||||
|
||||
.shortcut-title {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.menu-container {
|
||||
background-color: #fff;
|
||||
margin-top: 10px;
|
||||
margin: 0 15px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.item-icon {
|
||||
margin-right: 10px;
|
||||
width: 24px;
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
390
pages/record/appointment-record.vue
Normal file
@ -0,0 +1,390 @@
|
||||
<template>
|
||||
<full-page pageClass="record-page" :customScroll="true">
|
||||
<scroll-view
|
||||
class="record-scroll"
|
||||
scroll-y="true"
|
||||
refresher-enabled="true"
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="refreshRecords"
|
||||
>
|
||||
<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">></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">{{ statusText(item) }}</view>
|
||||
<view class="record-row">
|
||||
<text class="row-label">【预约类型】</text>
|
||||
<text class="row-value strong">{{ appointmentTypeText(item) }}</text>
|
||||
</view>
|
||||
<view class="record-row">
|
||||
<text class="row-label">【{{ practitionerLabel(item) }}】</text>
|
||||
<text class="row-value strong">{{ practitionerText(item) }}</text>
|
||||
</view>
|
||||
<view class="record-row">
|
||||
<text class="row-label">【预约日期】</text>
|
||||
<text class="row-value">{{ appointmentDateText(item) }}</text>
|
||||
</view>
|
||||
<view class="record-row">
|
||||
<text class="row-label">【预约时间】</text>
|
||||
<text class="row-value">{{ item.timeRange || "-" }}</text>
|
||||
</view>
|
||||
<view class="record-row">
|
||||
<text class="row-label">【预约项目】</text>
|
||||
<text class="row-value">{{ projectText(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-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 refreshing = ref(false);
|
||||
|
||||
const statusMap = {
|
||||
pending: { label: "未到院" },
|
||||
confirmed: { label: "已到院" },
|
||||
no_show: { label: "爽约" },
|
||||
};
|
||||
|
||||
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 formatDate(ts) {
|
||||
const d = toDate(ts);
|
||||
if (!d) return "";
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
||||
}
|
||||
|
||||
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: `${start.getFullYear()}-${pad(start.getMonth() + 1)}-01`,
|
||||
end: `${end.getFullYear()}-${pad(end.getMonth() + 1)}-${pad(end.getDate())}`,
|
||||
};
|
||||
}
|
||||
|
||||
function appointmentDateText(item) {
|
||||
return item?.appointmentDateStr || formatDate(item?.appointmentDate || item?.startTime || item?.registrationTime) || "-";
|
||||
}
|
||||
|
||||
function statusText(item) {
|
||||
return statusMap[item?.status || "pending"]?.label || "未到院";
|
||||
}
|
||||
|
||||
function appointmentTypeText(item) {
|
||||
if (item?.appointmentType === "schedule") return item?.scheduleTtile || "排班";
|
||||
if (item?.appointmentType === "medical") return "复诊预约";
|
||||
return "治疗预约";
|
||||
}
|
||||
|
||||
function practitionerLabel(item) {
|
||||
return item?.appointmentType === "medical" ? "医生" : "治疗师";
|
||||
}
|
||||
|
||||
function practitionerText(item) {
|
||||
const id = item?.therapistUserId || "";
|
||||
if (item?.therapistName) return item.therapistName;
|
||||
if (id === "none-therapist" || id === "none-doctor") return "未指定人员";
|
||||
return staffNameMap.value[id] || id || "未指定人员";
|
||||
}
|
||||
|
||||
function projectText(item) {
|
||||
const projects = item?.treatmentProject;
|
||||
if (Array.isArray(projects)) {
|
||||
const names = projects
|
||||
.map((project) => {
|
||||
if (!project) return "";
|
||||
if (typeof project === "string") return project;
|
||||
return project.projectName || project.name || project.title || "";
|
||||
})
|
||||
.filter(Boolean);
|
||||
return names.length ? names.join("、") : "无";
|
||||
}
|
||||
if (typeof projects === "string" && projects) return projects;
|
||||
return "无";
|
||||
}
|
||||
|
||||
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=appointment&corpId=${corp}&teamId=${team}&customerId=${customer}`,
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}, {});
|
||||
}
|
||||
|
||||
async function loadRecords(options = {}) {
|
||||
const { silent = false } = options;
|
||||
if (!corpId.value || !customerId.value) {
|
||||
records.value = [];
|
||||
return;
|
||||
}
|
||||
if (!silent) loading.value = true;
|
||||
try {
|
||||
const range = monthRange(selectedMonth.value);
|
||||
const res = await api(
|
||||
"getAppointmentRegistration",
|
||||
{
|
||||
corpId: corpId.value,
|
||||
customerId: customerId.value,
|
||||
appointmentDateStart: range.start,
|
||||
appointmentDateEnd: range.end,
|
||||
page: 1,
|
||||
pageSize: 200,
|
||||
sortBy: "appointmentDate",
|
||||
sortOrder: "desc",
|
||||
},
|
||||
false
|
||||
);
|
||||
if (!res?.success) {
|
||||
toast(res?.message || "加载预约记录失败");
|
||||
records.value = [];
|
||||
return;
|
||||
}
|
||||
records.value = (Array.isArray(res.data) ? res.data : []).sort((a, b) => {
|
||||
const aTime = Number(a.appointmentDate || a.startTime || a.registrationTime || 0);
|
||||
const bTime = Number(b.appointmentDate || b.startTime || b.registrationTime || 0);
|
||||
return bTime - aTime;
|
||||
});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshRecords() {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await loadStaffNameMap();
|
||||
await loadRecords({ silent: true });
|
||||
} finally {
|
||||
refreshing.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>
|
||||
.record-page :deep(.page-scroll) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.record-scroll {
|
||||
height: 100%;
|
||||
background: #e9edf3;
|
||||
}
|
||||
|
||||
.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-card::before {
|
||||
display: none;
|
||||
}
|
||||
.record-status {
|
||||
position: absolute;
|
||||
top: 24rpx;
|
||||
right: 24rpx;
|
||||
color: #333;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.record-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
gap: 0;
|
||||
padding: 7rpx 112rpx 7rpx 0;
|
||||
font-size: 27rpx;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
.record-row:first-of-type {
|
||||
padding-top: 0;
|
||||
}
|
||||
.row-label {
|
||||
flex-shrink: 0;
|
||||
color: #6b7280;
|
||||
font-weight: 700;
|
||||
}
|
||||
.row-value {
|
||||
min-width: 0;
|
||||
text-align: left;
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
.strong {
|
||||
color: #333;
|
||||
font-weight: 700;
|
||||
}
|
||||
.empty {
|
||||
padding: 120rpx 0;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
364
pages/record/treatment-record.vue
Normal file
@ -0,0 +1,364 @@
|
||||
<template>
|
||||
<full-page pageClass="record-page" :customScroll="true">
|
||||
<scroll-view class="record-scroll" scroll-y="true" refresher-enabled="true" :refresher-triggered="refreshing"
|
||||
@refresherrefresh="refreshRecords">
|
||||
<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">></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">{{ item.deductUsageCount || 0 }}</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 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 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>
|
||||
</scroll-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 refreshing = 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 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(options = {}) {
|
||||
const { silent = false } = options;
|
||||
if (!corpId.value || !customerId.value) {
|
||||
records.value = [];
|
||||
return;
|
||||
}
|
||||
if (!silent) 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 refreshRecords() {
|
||||
if (refreshing.value) return;
|
||||
refreshing.value = true;
|
||||
try {
|
||||
await loadStaffNameMap();
|
||||
await loadRecords({ silent: true });
|
||||
} finally {
|
||||
refreshing.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>
|
||||
.record-page :deep(.page-scroll) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.record-scroll {
|
||||
height: 100%;
|
||||
background: #e9edf3;
|
||||
}
|
||||
|
||||
.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>
|
||||
@ -12,6 +12,34 @@ export default [
|
||||
path: 'pages/login/redirect-page',
|
||||
meta: { title: '柚健康' },
|
||||
},
|
||||
{
|
||||
path: 'pages/experience-coupon/claim',
|
||||
meta: { title: '领取体验券', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/experience-coupon/my-rights',
|
||||
meta: { title: '我的权益', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/experience-coupon/select-rights-archive',
|
||||
meta: { title: '选择档案', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/experience-coupon/my-coupons',
|
||||
meta: { title: '我的体验券', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/experience-coupon/wallet',
|
||||
meta: { title: '我的卡包', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/record/treatment-record',
|
||||
meta: { title: '治疗记录', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/record/appointment-record',
|
||||
meta: { title: '预约记录', login: true }
|
||||
},
|
||||
{
|
||||
path: 'pages/archive/archive-manage',
|
||||
meta: { title: '档案管理', login: true }
|
||||
|
||||
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 724 B |
|
Before Width: | Height: | Size: 886 B After Width: | Height: | Size: 339 B |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 494 B |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 627 B |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 16 KiB |
@ -26,7 +26,7 @@ export default defineStore("accountStore", () => {
|
||||
|
||||
async function login(phoneCode = '', options = {}) {
|
||||
if (loading.value) return;
|
||||
if (account.value && account.value.mobile) {
|
||||
if (account.value && account.value.mobile && !options.forceVerify) {
|
||||
return account.value
|
||||
}
|
||||
loading.value = true;
|
||||
@ -54,6 +54,12 @@ export default defineStore("accountStore", () => {
|
||||
|
||||
// initIMAfterLogin(openid.value)
|
||||
return normalizedAccount
|
||||
} else {
|
||||
account.value = null;
|
||||
openid.value = '';
|
||||
uni.removeStorageSync('account');
|
||||
uni.removeStorageSync('openid');
|
||||
return
|
||||
}
|
||||
}
|
||||
if (!options.silent) toast('登录失败,请重新登录');
|
||||
@ -154,9 +160,9 @@ export default defineStore("accountStore", () => {
|
||||
const unionid = account.value?.unionid;
|
||||
const openid = account.value?.openid;
|
||||
if (!(normalizedCorpId && unionid && openid)) {
|
||||
externalUserId.value = '';
|
||||
return
|
||||
};
|
||||
externalUserId.value = '';
|
||||
return
|
||||
};
|
||||
const res = await api('getUnionidToExternalUserid', { unionid, openid, corpId: normalizedCorpId }, false);
|
||||
const id = res && res.success && typeof res.data === 'string' && res.data.trim() ? res.data.trim() : '';
|
||||
externalUserId.value = id;
|
||||
|
||||
10
utils/api.js
@ -13,6 +13,7 @@ const urlsConfig = {
|
||||
bindWxappWithTeam: 'bindWxappWithTeam',
|
||||
getWxappRelateTeams: 'getWxappRelateTeams',
|
||||
getTeamMemberAvatarsAndName: "getTeamMemberAvatarsAndName",
|
||||
getAllCorpMemberIncludeDeleted: "getAllCorpMemberIncludeDeleted",
|
||||
getMiniAppHomeStats: "getMiniAppHomeStats",
|
||||
getResponsiblePerson: 'getTeamResponsiblePerson',
|
||||
relateWxappTeamByExternalUserId: 'relateWxappTeamByExternalUserId',
|
||||
@ -54,9 +55,18 @@ const urlsConfig = {
|
||||
addMedicalRecord: 'addMedicalRecord',
|
||||
authCustomerToTeam: 'authCustomerToTeam', // 授权客户到团队
|
||||
bindMiniAppArchive: "bindMiniAppArchive",
|
||||
claimExperienceCoupon: "claimExperienceCoupon",
|
||||
voidExperienceCouponIssue: "voidExperienceCouponIssue",
|
||||
getCustomerByCustomerId: 'getCustomerByCustomerId',
|
||||
getCustomerExperienceCoupons: "getCustomerExperienceCoupons",
|
||||
getExperienceCouponIssueDetail: "getExperienceCouponIssueDetail",
|
||||
getExperienceCouponIssueList: "getExperienceCouponIssueList",
|
||||
getMiniAppCustomers: 'getMiniAppCustomers',
|
||||
getTeamCustomers: 'getTeamCustomers',
|
||||
getTreatmentRecord: "getTreatmentRecord",
|
||||
getDeductRecord: "getDeductRecord",
|
||||
getAppointmentRecord: "getAppointmentRecord",
|
||||
getAppointmentRegistration: "getAppointmentRegistration",
|
||||
getUnbindMiniAppCustomers: 'getUnbindMiniAppCustomers',
|
||||
getCustomerMedicalRecord: 'getCustomerMedicalRecord',
|
||||
getMedicalRecordById: 'getMedicalRecordById',
|
||||
|
||||