Compare commits
17 Commits
main
...
dev-ticket
| Author | SHA1 | Date | |
|---|---|---|---|
| 57803051e1 | |||
| fe7583017d | |||
| 94a515924b | |||
|
|
56c08eb255 | ||
| bbe50bdd72 | |||
| 6aa126bc81 | |||
| 58c9329eb6 | |||
| 9f5331cd3b | |||
| 92fe63f308 | |||
|
|
2dc3f07802 | ||
| edb9ee5c38 | |||
| b1a6e58a6f | |||
| d9b271e757 | |||
| e23ab0f6d3 | |||
|
|
68436fc7f4 | ||
|
|
2ac04ba97e | ||
|
|
f13e6ede64 |
47
components/form-template/form-cell/form-evaluated-joint.vue
Normal file
47
components/form-template/form-cell/form-evaluated-joint.vue
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<common-cell :name="name" :required="required">
|
||||||
|
<view class="joint-row">
|
||||||
|
<picker mode="selector" :range="jointOptions" :disabled="disableChange" @change="changeJoint">
|
||||||
|
<view class="joint-picker" :class="jointType ? '' : 'form__placeholder'">{{ jointType || '请选择关节类型' }}</view>
|
||||||
|
</picker>
|
||||||
|
<picker mode="selector" :range="jointSideOptions" :disabled="disableChange" @change="changeSide">
|
||||||
|
<view class="joint-picker" :class="jointSide ? '' : 'form__placeholder'">{{ jointSide || '请选择侧别' }}</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</common-cell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import commonCell from '../common-cell.vue';
|
||||||
|
|
||||||
|
const emits = defineEmits(['change']);
|
||||||
|
const props = defineProps({
|
||||||
|
form: { type: Object, default: () => ({}) },
|
||||||
|
name: { default: '' },
|
||||||
|
title: { default: '' },
|
||||||
|
range: { type: Array, default: () => [] },
|
||||||
|
required: { type: Boolean, default: false },
|
||||||
|
disableChange: { type: Boolean, default: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
const jointOptions = computed(() => props.range.length ? props.range : ['膝关节', '髋关节']);
|
||||||
|
const jointSideOptions = ['左侧', '右侧', '双侧'];
|
||||||
|
const jointType = computed(() => props.form?.[props.title] || '');
|
||||||
|
const jointSide = computed(() => props.form?.jointSide || '');
|
||||||
|
|
||||||
|
function changeJoint(event) {
|
||||||
|
emits('change', { title: props.title, value: jointOptions.value[event.detail.value] });
|
||||||
|
}
|
||||||
|
function changeSide(event) {
|
||||||
|
emits('change', { title: 'jointSide', value: jointSideOptions[event.detail.value] });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '../cell-style.css';
|
||||||
|
|
||||||
|
.joint-row { display: flex; gap: 16rpx; width: 100%; }
|
||||||
|
.joint-row picker { flex: 1; min-width: 0; }
|
||||||
|
.joint-picker { padding: 12rpx 16rpx; border: 1rpx solid #dcdfe6; border-radius: 8rpx; font-size: 28rpx; }
|
||||||
|
</style>
|
||||||
48
components/form-template/form-cell/form-exercise-level.vue
Normal file
48
components/form-template/form-cell/form-exercise-level.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<common-cell :name="name" :required="required">
|
||||||
|
<view class="exercise-row">
|
||||||
|
<input class="exercise-input" type="number" :disabled="disableChange" :value="frequency" placeholder="次数" @input="changeFrequency" />
|
||||||
|
<text class="exercise-unit">次/周</text>
|
||||||
|
<input class="exercise-input" type="number" :disabled="disableChange" :value="duration" placeholder="时长" @input="changeDuration" />
|
||||||
|
<text class="exercise-unit">min/次</text>
|
||||||
|
</view>
|
||||||
|
</common-cell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import commonCell from '../common-cell.vue';
|
||||||
|
|
||||||
|
const emits = defineEmits(['change']);
|
||||||
|
const props = defineProps({
|
||||||
|
form: { type: Object, default: () => ({}) },
|
||||||
|
name: { default: '' },
|
||||||
|
title: { default: '' },
|
||||||
|
required: { type: Boolean, default: false },
|
||||||
|
disableChange: { type: Boolean, default: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
const values = computed(() => {
|
||||||
|
const matched = String(props.form?.[props.title] || '').match(/^\s*(\d*)\s*次\/周\s*[;;]\s*(\d*)\s*min\/次\s*$/);
|
||||||
|
return matched ? { frequency: matched[1], duration: matched[2] } : { frequency: '', duration: '' };
|
||||||
|
});
|
||||||
|
const frequency = computed(() => values.value.frequency);
|
||||||
|
const duration = computed(() => values.value.duration);
|
||||||
|
|
||||||
|
function emitValue(nextFrequency, nextDuration) {
|
||||||
|
emits('change', {
|
||||||
|
title: props.title,
|
||||||
|
value: !nextFrequency && !nextDuration ? '' : `${nextFrequency || ''}次/周;${nextDuration || ''}min/次`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function changeFrequency(event) { emitValue(event.detail.value, duration.value); }
|
||||||
|
function changeDuration(event) { emitValue(frequency.value, event.detail.value); }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '../cell-style.css';
|
||||||
|
|
||||||
|
.exercise-row { display: flex; align-items: center; gap: 10rpx; white-space: nowrap; }
|
||||||
|
.exercise-input { width: 96rpx; min-width: 96rpx; padding: 8rpx 10rpx; border: 1rpx solid #dcdfe6; border-radius: 8rpx; font-size: 28rpx; }
|
||||||
|
.exercise-unit { flex-shrink: 0; font-size: 26rpx; color: #303133; }
|
||||||
|
</style>
|
||||||
58
components/form-template/form-cell/form-select-and-other.vue
Normal file
58
components/form-template/form-cell/form-select-and-other.vue
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<common-cell :name="name" :required="required">
|
||||||
|
<view class="select-other">
|
||||||
|
<picker mode="selector" :range="range" :disabled="disableChange" @change="changeSelect">
|
||||||
|
<view class="select-other__picker" :class="selectedValue ? '' : 'form__placeholder'">{{ selectedValue || '请选择' }}</view>
|
||||||
|
</picker>
|
||||||
|
<input v-if="showOther" class="select-other__input" :disabled="disableChange" :value="otherValue" placeholder="请填写其他原因" @input="changeOther" />
|
||||||
|
</view>
|
||||||
|
</common-cell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import commonCell from '../common-cell.vue';
|
||||||
|
|
||||||
|
const emits = defineEmits(['change']);
|
||||||
|
const props = defineProps({
|
||||||
|
form: { type: Object, default: () => ({}) },
|
||||||
|
name: { default: '' },
|
||||||
|
title: { default: '' },
|
||||||
|
range: { type: Array, default: () => [] },
|
||||||
|
otherFiled: { default: '' },
|
||||||
|
otherField: { default: '' },
|
||||||
|
required: { type: Boolean, default: false },
|
||||||
|
disableChange: { type: Boolean, default: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
const value = computed(() => props.form?.[props.title] || '');
|
||||||
|
const otherOption = computed(() => props.otherFiled || props.otherField || props.range.find((item) => /^(其它|其他)$/.test(item)) || '其它');
|
||||||
|
const isPreset = computed(() => props.range.includes(value.value));
|
||||||
|
const selectingOther = ref(false);
|
||||||
|
const showOther = computed(() => selectingOther.value || (Boolean(value.value) && !isPreset.value));
|
||||||
|
const selectedValue = computed(() => showOther.value ? otherOption.value : value.value);
|
||||||
|
const otherValue = computed(() => showOther.value ? value.value : '');
|
||||||
|
|
||||||
|
watch(value, (nextValue) => {
|
||||||
|
if (nextValue && props.range.includes(nextValue)) selectingOther.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
function changeSelect(event) {
|
||||||
|
const selected = props.range[event.detail.value];
|
||||||
|
if (selected === otherOption.value) {
|
||||||
|
selectingOther.value = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectingOther.value = false;
|
||||||
|
emits('change', { title: props.title, value: selected });
|
||||||
|
}
|
||||||
|
function changeOther(event) { emits('change', { title: props.title, value: event.detail.value }); }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '../cell-style.css';
|
||||||
|
|
||||||
|
.select-other { width: 100%; }
|
||||||
|
.select-other__picker, .select-other__input { box-sizing: border-box; width: 100%; padding: 12rpx 16rpx; border: 1rpx solid #dcdfe6; border-radius: 8rpx; font-size: 28rpx; }
|
||||||
|
.select-other__input { margin-top: 14rpx; }
|
||||||
|
</style>
|
||||||
@ -10,6 +10,12 @@
|
|||||||
@change="change" />
|
@change="change" />
|
||||||
<form-select v-else-if="attrs.type === 'select'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
<form-select v-else-if="attrs.type === 'select'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
@change="change" />
|
@change="change" />
|
||||||
|
<form-evaluated-joint v-else-if="attrs.type === 'evaluatedJoint'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
|
@change="change" />
|
||||||
|
<form-exercise-level v-else-if="attrs.type === 'exerciseLevel'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
|
@change="change" />
|
||||||
|
<form-select-and-other v-else-if="attrs.type === 'selectAndOther'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
|
@change="change" />
|
||||||
<form-textarea v-else-if="attrs.type === 'textarea'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
<form-textarea v-else-if="attrs.type === 'textarea'" v-bind="attrs" :form="form" :disableChange="disableChange"
|
||||||
@change="change" />
|
@change="change" />
|
||||||
<form-mult-disease v-else-if="attrs.type === 'selfMultipleDiseases'" v-bind="attrs" :form="form" @change="change"
|
<form-mult-disease v-else-if="attrs.type === 'selfMultipleDiseases'" v-bind="attrs" :form="form" @change="change"
|
||||||
@ -33,6 +39,9 @@ import { useAttrs } from 'vue';
|
|||||||
|
|
||||||
import formInput from './form-input.vue';
|
import formInput from './form-input.vue';
|
||||||
import formSelect from './form-select.vue';
|
import formSelect from './form-select.vue';
|
||||||
|
import formEvaluatedJoint from './form-evaluated-joint.vue';
|
||||||
|
import formExerciseLevel from './form-exercise-level.vue';
|
||||||
|
import formSelectAndOther from './form-select-and-other.vue';
|
||||||
import formRadio from './form-radio.vue';
|
import formRadio from './form-radio.vue';
|
||||||
import formDatepicker from './form-datepicker.vue';
|
import formDatepicker from './form-datepicker.vue';
|
||||||
import formRegion from './form-region.vue';
|
import formRegion from './form-region.vue';
|
||||||
|
|||||||
@ -33,7 +33,7 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const formCellType = ['input', 'select', 'date', 'radio', 'region', 'textarea', 'multiSelectAndOther', 'selfMultipleDiseases', 'files','diagnosis','positiveFind'];
|
const formCellType = ['input', 'select', 'date', 'radio', 'region', 'textarea', 'multiSelectAndOther', 'selectAndOther', 'selfMultipleDiseases', 'files', 'diagnosis', 'positiveFind', 'evaluatedJoint', 'exerciseLevel'];
|
||||||
const formCellTitle = ['surgicalHistory'];
|
const formCellTitle = ['surgicalHistory'];
|
||||||
const customCellType = ['BMI', 'bloodPressure'];
|
const customCellType = ['BMI', 'bloodPressure'];
|
||||||
const disabledMap = computed(() => props.disableTitles.reduce((m, i) => {
|
const disabledMap = computed(() => props.disableTitles.reduce((m, i) => {
|
||||||
|
|||||||
91
hooks/use-team-access.js
Normal file
91
hooks/use-team-access.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import api from "@/utils/api";
|
||||||
|
import { set } from "@/utils/cache";
|
||||||
|
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||||
|
|
||||||
|
function buildTeamLoginUrl(redirectUrl) {
|
||||||
|
const query = [
|
||||||
|
"source=teamInvite",
|
||||||
|
`redirectUrl=${encodeURIComponent(redirectUrl || "")}`,
|
||||||
|
].join("&");
|
||||||
|
return `/pages/login/login?${query}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTeamAccess() {
|
||||||
|
async function getTeamInfo({ corpId, teamId, fallbackCorpName = "" }) {
|
||||||
|
if (!corpId || !teamId) return null;
|
||||||
|
try {
|
||||||
|
const res = await api(
|
||||||
|
"getTeamData",
|
||||||
|
{ corpId, teamId, withCorpName: true },
|
||||||
|
false
|
||||||
|
);
|
||||||
|
const team = res?.data || null;
|
||||||
|
if (!team) return null;
|
||||||
|
return {
|
||||||
|
...team,
|
||||||
|
corpName: team.corpName || team.corp_name || fallbackCorpName,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("getTeamData failed", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openTeamLogin({
|
||||||
|
corpId,
|
||||||
|
teamId,
|
||||||
|
redirectUrl,
|
||||||
|
fallbackCorpName = "",
|
||||||
|
corpUserId = "",
|
||||||
|
externalUserId = "",
|
||||||
|
}) {
|
||||||
|
if (!corpId || !teamId) {
|
||||||
|
return { success: false, message: "团队信息缺失,暂无法授权" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const team = await getTeamInfo({ corpId, teamId, fallbackCorpName });
|
||||||
|
set("invite-team-info", {
|
||||||
|
corpId,
|
||||||
|
teamId,
|
||||||
|
corpUserId,
|
||||||
|
externalUserId,
|
||||||
|
corpName: team?.corpName || fallbackCorpName,
|
||||||
|
teamName: team?.name || team?.teamName || "",
|
||||||
|
avatars: Array.isArray(team?.memberList)
|
||||||
|
? team.memberList.map((member) => member?.avatar || "").filter(Boolean)
|
||||||
|
: [],
|
||||||
|
});
|
||||||
|
uni.navigateTo({ url: buildTeamLoginUrl(redirectUrl) });
|
||||||
|
return { success: true, team };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureTeamAdded({ appid, account, getTeams, corpId, teamId }) {
|
||||||
|
if (!appid || !account?.openid || !corpId || !teamId) {
|
||||||
|
return { success: false, message: "团队信息缺失,暂无法绑定" };
|
||||||
|
}
|
||||||
|
const teams = await getTeams();
|
||||||
|
const linked = (teams || []).some(
|
||||||
|
(team) =>
|
||||||
|
normalizeCorpId(team.corpId) === normalizeCorpId(corpId) &&
|
||||||
|
String(team.teamId) === String(teamId)
|
||||||
|
);
|
||||||
|
if (linked) return { success: true, alreadyLinked: true };
|
||||||
|
|
||||||
|
const res = await api(
|
||||||
|
"bindWxappWithTeam",
|
||||||
|
{ appid, corpId, teamId, openid: account.openid },
|
||||||
|
false
|
||||||
|
);
|
||||||
|
if (!res?.success) {
|
||||||
|
return { success: false, message: res?.message || "添加团队失败" };
|
||||||
|
}
|
||||||
|
await getTeams();
|
||||||
|
return { success: true, alreadyLinked: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getTeamInfo,
|
||||||
|
openTeamLogin,
|
||||||
|
ensureTeamAdded,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -10,12 +10,12 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<button-footer :showCancel="customerId ? true : false" cancelText="删除" :confirmText="healthTypes.length?'下一步':'保存'" @cancel="unBindArchive()"
|
<button-footer :showCancel="customerId ? true : false" cancelText="删除"
|
||||||
@confirm="confirm()" />
|
:confirmText="healthTypes.length ? '下一步' : '保存'" @cancel="unBindArchive()" @confirm="confirm()" />
|
||||||
</template>
|
</template>
|
||||||
</full-page>
|
</full-page>
|
||||||
<bind-popup :customers="customers" :corpName="corpName" :enableHis="enableHis" :visible="visible" @close="visible = false"
|
<bind-popup :customers="customers" :corpName="corpName" :enableHis="enableHis" :visible="visible"
|
||||||
@confirm="bindArchive($event)" />
|
@close="visible = false" @confirm="bindArchive($event)" />
|
||||||
<verify-popup :visible="verifyVisible" @close="verifyVisible = false" />
|
<verify-popup :visible="verifyVisible" @close="verifyVisible = false" />
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -44,6 +44,7 @@ const { getExternalUserId } = useAccount()
|
|||||||
const corpId = ref('');
|
const corpId = ref('');
|
||||||
const corpName = ref('');
|
const corpName = ref('');
|
||||||
const corpUserId = ref('');
|
const corpUserId = ref('');
|
||||||
|
const bindCustomerId = ref('');
|
||||||
const referenceCustomerId = ref('');
|
const referenceCustomerId = ref('');
|
||||||
const customer = ref({});
|
const customer = ref({});
|
||||||
const customerId = ref('');
|
const customerId = ref('');
|
||||||
@ -59,6 +60,7 @@ const visible = ref(false);
|
|||||||
const referenceCustomer = ref(null)
|
const referenceCustomer = ref(null)
|
||||||
const healthTypes = ref([]);
|
const healthTypes = ref([]);
|
||||||
const enableHis = ref(false);
|
const enableHis = ref(false);
|
||||||
|
const source = ref('');
|
||||||
|
|
||||||
const formData = computed(() => {
|
const formData = computed(() => {
|
||||||
return { ...customer.value, ...form.value, mobile: account.value?.mobile }
|
return { ...customer.value, ...form.value, mobile: account.value?.mobile }
|
||||||
@ -166,6 +168,11 @@ async function addArchive() {
|
|||||||
set('home-invite-team-info', { teamId: teamId.value })
|
set('home-invite-team-info', { teamId: teamId.value })
|
||||||
if (res && res.success) {
|
if (res && res.success) {
|
||||||
uni.$emit('reloadTeamCustomers')
|
uni.$emit('reloadTeamCustomers')
|
||||||
|
if (source.value === 'experienceCoupon') {
|
||||||
|
await toast('档案创建成功');
|
||||||
|
uni.navigateBack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// getTeam(corpId.value, teamId.value, res.data.id);
|
// getTeam(corpId.value, teamId.value, res.data.id);
|
||||||
if (healthTypes.value.length) {
|
if (healthTypes.value.length) {
|
||||||
const nextType = healthTypes.value[0];
|
const nextType = healthTypes.value[0];
|
||||||
@ -187,6 +194,20 @@ async function getResponsiblePerson() {
|
|||||||
return res && res.data ? res.data : ''
|
return res && res.data ? res.data : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shouldBackAfterArchiveBound() {
|
||||||
|
return ['experienceCoupon', 'appointmentRegistration'].includes(source.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function backAfterArchiveBound() {
|
||||||
|
if (shouldBackAfterArchiveBound()) {
|
||||||
|
uni.navigateBack()
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uni.switchTab({
|
||||||
|
url: '/pages/home/home'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function bindArchive(customerId) {
|
async function bindArchive(customerId) {
|
||||||
let responsiblePerson = '';
|
let responsiblePerson = '';
|
||||||
if (externalUserId.value) {
|
if (externalUserId.value) {
|
||||||
@ -197,9 +218,7 @@ async function bindArchive(customerId) {
|
|||||||
if (res && res.success) {
|
if (res && res.success) {
|
||||||
await toast('绑定成功');
|
await toast('绑定成功');
|
||||||
uni.$emit('reloadTeamCustomers')
|
uni.$emit('reloadTeamCustomers')
|
||||||
uni.switchTab({
|
backAfterArchiveBound()
|
||||||
url: '/pages/home/home'
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
toast(res?.message || '绑定失败');
|
toast(res?.message || '绑定失败');
|
||||||
}
|
}
|
||||||
@ -209,11 +228,15 @@ async function init() {
|
|||||||
if (customerId.value) {
|
if (customerId.value) {
|
||||||
await getCustomer();
|
await getCustomer();
|
||||||
} else {
|
} else {
|
||||||
const res = await getArchives();
|
await getExternalUserId(corpId.value);
|
||||||
|
const res = bindCustomerId.value ? await getExperienceCouponBindArchive() : await getArchives();
|
||||||
if (res.length > 0) {
|
if (res.length > 0) {
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
|
} else if (bindCustomerId.value || shouldBackAfterArchiveBound()) {
|
||||||
|
await toast('指定绑定档案不存在或已绑定');
|
||||||
|
uni.navigateBack();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
getExternalUserId(corpId.value);
|
|
||||||
getTeam(corpId.value, teamId.value)
|
getTeam(corpId.value, teamId.value)
|
||||||
}
|
}
|
||||||
await getBaseForm();
|
await getBaseForm();
|
||||||
@ -223,8 +246,17 @@ async function init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getExperienceCouponBindArchive() {
|
||||||
|
const res = await api('getCustomerByCustomerId', { corpId: corpId.value, customerId: bindCustomerId.value });
|
||||||
|
const data = res && res.success && res.data ? res.data : null;
|
||||||
|
customers.value = data ? [data] : [];
|
||||||
|
corpName.value = res && res.corpName ? res.corpName : corpName.value;
|
||||||
|
enableHis.value = false;
|
||||||
|
return customers.value;
|
||||||
|
}
|
||||||
|
|
||||||
async function getArchives() {
|
async function getArchives() {
|
||||||
const res = await api('getUnbindMiniAppCustomers', { corpId: corpId.value, mobile: account.value?.mobile || '' });
|
const res = await api('getUnbindMiniAppCustomers', { corpId: corpId.value, mobile: account.value?.mobile || '', externalUserId: externalUserId.value });
|
||||||
customers.value = res && Array.isArray(res.data) ? res.data : [];
|
customers.value = res && Array.isArray(res.data) ? res.data : [];
|
||||||
corpName.value = res && res.corpName ? res.corpName : '';
|
corpName.value = res && res.corpName ? res.corpName : '';
|
||||||
enableHis.value = res && res.enableHis ? res.enableHis : false;
|
enableHis.value = res && res.enableHis ? res.enableHis : false;
|
||||||
@ -305,8 +337,10 @@ onLoad(options => {
|
|||||||
teamId.value = options.teamId;
|
teamId.value = options.teamId;
|
||||||
corpId.value = options.corpId;
|
corpId.value = options.corpId;
|
||||||
customerId.value = options.id || '';
|
customerId.value = options.id || '';
|
||||||
|
bindCustomerId.value = options.bindCustomerId || '';
|
||||||
corpUserId.value = options.corpUserId || '';
|
corpUserId.value = options.corpUserId || '';
|
||||||
referenceCustomerId.value = options.referenceCustomerId || '';
|
referenceCustomerId.value = options.referenceCustomerId || '';
|
||||||
|
source.value = options.source || '';
|
||||||
if (referenceCustomerId.value) {
|
if (referenceCustomerId.value) {
|
||||||
getReferenceCustomer();
|
getReferenceCustomer();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<view>
|
||||||
<full-page>
|
<full-page>
|
||||||
<view class="claim-page">
|
<view class="claim-page">
|
||||||
<view v-if="tip" class="tip">{{ tip }}</view>
|
<view v-if="tip" class="tip">{{ tip }}</view>
|
||||||
<view v-else class="tip">加载中...</view>
|
<view v-else class="tip">加载中...</view>
|
||||||
</view>
|
</view>
|
||||||
|
</full-page>
|
||||||
|
|
||||||
|
<!-- Keep the fixed overlay outside full-page's scroll-view for iOS compatibility. -->
|
||||||
<view v-if="posterVisible" class="poster-mask">
|
<view v-if="posterVisible" class="poster-mask">
|
||||||
<view class="poster-dialog">
|
<view class="poster-dialog">
|
||||||
<image class="poster-image" :src="issue?.posterUrl || ''" mode="widthFix" />
|
<image
|
||||||
|
v-if="issue?.posterUrl"
|
||||||
|
class="poster-image"
|
||||||
|
:src="issue.posterUrl"
|
||||||
|
mode="aspectFit"
|
||||||
|
/>
|
||||||
|
<view v-else class="poster-image poster-image--placeholder">体验券</view>
|
||||||
<view class="poster-content">{{ buildClaimContent() }}</view>
|
<view class="poster-content">{{ buildClaimContent() }}</view>
|
||||||
<view class="poster-btn" :class="{ disabled: claiming }" @click="acceptCoupon">
|
<view class="poster-btn" :class="{ disabled: claiming }" @click="acceptCoupon">
|
||||||
{{ claiming ? "领取中..." : "接受" }}
|
{{ claiming ? "领取中..." : "接受" }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</full-page>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -23,21 +32,29 @@ import { storeToRefs } from "pinia";
|
|||||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
import useAccount from "@/store/account";
|
import useAccount from "@/store/account";
|
||||||
import api from "@/utils/api";
|
import api from "@/utils/api";
|
||||||
import { confirm, hideLoading, loading, toast } from "@/utils/widget";
|
import { hideLoading, loading, toast } from "@/utils/widget";
|
||||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||||
|
import { useTeamAccess } from "@/hooks/use-team-access";
|
||||||
import FullPage from "@/components/full-page.vue";
|
import FullPage from "@/components/full-page.vue";
|
||||||
|
|
||||||
|
const env = __VITE_ENV__;
|
||||||
|
const appid = env.MP_WX_APP_ID;
|
||||||
const { account } = storeToRefs(useAccount());
|
const { account } = storeToRefs(useAccount());
|
||||||
const { login } = useAccount();
|
const { getTeams, login } = useAccount();
|
||||||
|
const { openTeamLogin: openTeamInviteLogin, ensureTeamAdded: ensureJoinedTeam } = useTeamAccess();
|
||||||
|
|
||||||
const corpId = ref("");
|
const corpId = ref("");
|
||||||
const issueId = ref("");
|
const issueId = ref("");
|
||||||
const memberId = ref("");
|
const memberId = ref("");
|
||||||
const issue = ref(null);
|
const issue = ref(null);
|
||||||
|
const issueCustomer = ref(null);
|
||||||
const tip = ref("");
|
const tip = ref("");
|
||||||
const claiming = ref(false);
|
const claiming = ref(false);
|
||||||
const autoPrompted = ref(false);
|
const autoPrompted = ref(false);
|
||||||
const posterVisible = ref(false);
|
const posterVisible = ref(false);
|
||||||
|
const archiveBindPending = ref(false);
|
||||||
|
const bindingTeamId = ref("");
|
||||||
|
const bindCorpName = ref("");
|
||||||
|
|
||||||
const projectNameText = computed(() => {
|
const projectNameText = computed(() => {
|
||||||
const projects = Array.isArray(issue.value?.projectSnapshot) ? issue.value.projectSnapshot : [];
|
const projects = Array.isArray(issue.value?.projectSnapshot) ? issue.value.projectSnapshot : [];
|
||||||
@ -54,7 +71,7 @@ async function ensureLogin() {
|
|||||||
if (!account.value) await login();
|
if (!account.value) await login();
|
||||||
if (!account.value) {
|
if (!account.value) {
|
||||||
tip.value = "请先登录后再领取体验券";
|
tip.value = "请先登录后再领取体验券";
|
||||||
uni.navigateTo({ url: "/pages/login/login" });
|
await openTeamLogin();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -77,11 +94,10 @@ async function loadIssueDetail() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hasBoundArchive() {
|
async function getIssueCustomer({ force = false } = {}) {
|
||||||
const openid = account.value?.openid || "";
|
if (!corpId.value || !memberId.value) return null;
|
||||||
if (!openid || !corpId.value) return false;
|
if (issueCustomer.value && !force) return issueCustomer.value;
|
||||||
|
|
||||||
if (memberId.value) {
|
|
||||||
try {
|
try {
|
||||||
const detail = await api(
|
const detail = await api(
|
||||||
"getCustomerByCustomerId",
|
"getCustomerByCustomerId",
|
||||||
@ -89,41 +105,121 @@ async function hasBoundArchive() {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
const customer = detail?.data || null;
|
const customer = detail?.data || null;
|
||||||
if (customer && String(customer.miniAppId || "") === String(openid)) {
|
issueCustomer.value = customer;
|
||||||
return true;
|
bindCorpName.value = detail?.corpName || issue.value?.corpName || "";
|
||||||
}
|
const teamIds = Array.isArray(customer?.teamId) ? customer.teamId : [customer?.teamId];
|
||||||
|
bindingTeamId.value = issue.value?.teamId || teamIds.find(Boolean) || "";
|
||||||
|
return customer;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("getCustomerByCustomerId failed", e);
|
console.warn("getCustomerByCustomerId failed", e);
|
||||||
}
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
async function hasBoundArchive() {
|
||||||
uni.navigateTo({
|
const openid = account.value?.openid || "";
|
||||||
url: `/pages/archive/archive-manage?corpId=${encodeURIComponent(corpId.value || "")}`,
|
if (!openid) return false;
|
||||||
|
|
||||||
|
const customer = await getIssueCustomer({ force: true });
|
||||||
|
return Boolean(customer && String(customer.miniAppId || "") === String(openid));
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildClaimUrl() {
|
||||||
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(corpId.value || "")}`,
|
||||||
|
`issueId=${encodeURIComponent(issueId.value || "")}`,
|
||||||
|
memberId.value ? `memberId=${encodeURIComponent(memberId.value)}` : "",
|
||||||
|
].filter(Boolean).join("&");
|
||||||
|
return `/pages/experience-coupon/claim?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openTeamLogin() {
|
||||||
|
const customer = await getIssueCustomer();
|
||||||
|
if (!customer || !bindingTeamId.value) {
|
||||||
|
tip.value = "体验券发放档案缺少所属团队,暂无法领取";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const result = await openTeamInviteLogin({
|
||||||
|
corpId: corpId.value,
|
||||||
|
teamId: bindingTeamId.value,
|
||||||
|
redirectUrl: buildClaimUrl(),
|
||||||
|
fallbackCorpName: bindCorpName.value || issue.value?.corpName || "",
|
||||||
});
|
});
|
||||||
|
if (!result.success) {
|
||||||
|
tip.value = result.message;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensurePhoneAuthorized() {
|
||||||
|
if (account.value?.mobile) return true;
|
||||||
|
|
||||||
|
tip.value = "请先授权手机号后再领取体验券";
|
||||||
|
return openTeamLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureTeamAdded() {
|
||||||
|
const customer = await getIssueCustomer();
|
||||||
|
if (!customer || !bindingTeamId.value) {
|
||||||
|
tip.value = "体验券发放档案缺少所属团队,暂无法领取";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading("添加团队中...");
|
||||||
|
try {
|
||||||
|
const res = await ensureJoinedTeam({
|
||||||
|
appid,
|
||||||
|
account: account.value,
|
||||||
|
getTeams,
|
||||||
|
corpId: corpId.value,
|
||||||
|
teamId: bindingTeamId.value,
|
||||||
|
});
|
||||||
|
if (!res.success) {
|
||||||
|
tip.value = res.message;
|
||||||
|
toast(tip.value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildArchiveBindUrl() {
|
||||||
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(corpId.value || "")}`,
|
||||||
|
`teamId=${encodeURIComponent(bindingTeamId.value || "")}`,
|
||||||
|
`bindCustomerId=${encodeURIComponent(memberId.value || "")}`,
|
||||||
|
`source=experienceCoupon`,
|
||||||
|
].join("&");
|
||||||
|
return `/pages/archive/edit-archive?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function openArchiveBindPage() {
|
||||||
|
if (!issueCustomer.value || !bindingTeamId.value) {
|
||||||
|
toast("体验券发放档案不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
archiveBindPending.value = true;
|
||||||
|
uni.navigateTo({ url: buildArchiveBindUrl() });
|
||||||
|
}
|
||||||
|
|
||||||
|
function toTimestamp(value) {
|
||||||
|
if (!value) return 0;
|
||||||
|
const numeric = Number(value);
|
||||||
|
if (Number.isFinite(numeric)) return numeric;
|
||||||
|
const parsed = new Date(value).getTime();
|
||||||
|
return Number.isNaN(parsed) ? 0 : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIssueExpireAt() {
|
||||||
|
return toTimestamp(issue.value?.activityEndTime || issue.value?.displayExpireTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isExpiredIssue() {
|
function isExpiredIssue() {
|
||||||
const expireAt = Number(issue.value?.projectExpireTime || 0);
|
const expireAt = getIssueExpireAt();
|
||||||
if (expireAt && Date.now() > expireAt) return true;
|
return Boolean(expireAt && Date.now() > expireAt);
|
||||||
const rule = issue.value?.projectValidRuleSnapshot || {};
|
|
||||||
if (rule.type === "fixedDate" && rule.fixedDate && Date.now() > Number(rule.fixedDate)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function acceptCoupon() {
|
async function acceptCoupon() {
|
||||||
@ -141,6 +237,10 @@ async function acceptCoupon() {
|
|||||||
if (!res?.success) {
|
if (!res?.success) {
|
||||||
tip.value = res?.message || "领取失败";
|
tip.value = res?.message || "领取失败";
|
||||||
toast(tip.value);
|
toast(tip.value);
|
||||||
|
if (tip.value.includes("绑定本体验券发放的档案")) {
|
||||||
|
posterVisible.value = false;
|
||||||
|
openArchiveBindPage();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast("领取成功");
|
toast("领取成功");
|
||||||
@ -184,17 +284,7 @@ async function promptClaim() {
|
|||||||
|
|
||||||
const bound = await hasBoundArchive();
|
const bound = await hasBoundArchive();
|
||||||
if (!bound) {
|
if (!bound) {
|
||||||
tip.value = "请先绑定档案后再领取体验券";
|
openArchiveBindPage();
|
||||||
try {
|
|
||||||
await confirm("请先绑定档案后再领取体验券", {
|
|
||||||
title: "提示",
|
|
||||||
confirmText: "去绑定",
|
|
||||||
cancelText: "取消",
|
|
||||||
});
|
|
||||||
goBindArchive();
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,17 +295,39 @@ async function promptClaim() {
|
|||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
loading("加载中...");
|
loading("加载中...");
|
||||||
try {
|
try {
|
||||||
const okLogin = await ensureLogin();
|
|
||||||
if (!okLogin) return;
|
|
||||||
const okDetail = await loadIssueDetail();
|
const okDetail = await loadIssueDetail();
|
||||||
if (!okDetail) return;
|
if (!okDetail) return;
|
||||||
|
const okLogin = await ensureLogin();
|
||||||
|
if (!okLogin) return;
|
||||||
|
const phoneAuthorized = await ensurePhoneAuthorized();
|
||||||
|
if (!phoneAuthorized) return;
|
||||||
|
const teamAdded = await ensureTeamAdded();
|
||||||
|
if (!teamAdded) return;
|
||||||
await promptClaim();
|
await promptClaim();
|
||||||
} finally {
|
} finally {
|
||||||
hideLoading();
|
hideLoading();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad((options = {}) => {
|
function parseOptions(options = {}) {
|
||||||
|
const href = typeof options.q === "string" ? decodeURIComponent(options.q) : "";
|
||||||
|
const [, url = ""] = href.split("?");
|
||||||
|
return url.split("&").reduce((acc, cur) => {
|
||||||
|
if (!cur) return acc;
|
||||||
|
const [key, val = ''] = cur.split("=");
|
||||||
|
if (!key) return acc;
|
||||||
|
acc[key] = val
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
onLoad((opts = {}) => {
|
||||||
|
let options = {};
|
||||||
|
if (opts.q) {
|
||||||
|
options = { ...parseOptions(opts) }
|
||||||
|
} else {
|
||||||
|
options = { ...opts }
|
||||||
|
}
|
||||||
corpId.value = normalizeCorpId(options.corpId || "");
|
corpId.value = normalizeCorpId(options.corpId || "");
|
||||||
issueId.value = options.issueId || options.id || "";
|
issueId.value = options.issueId || options.id || "";
|
||||||
memberId.value = options.memberId || options.customerId || "";
|
memberId.value = options.memberId || options.customerId || "";
|
||||||
@ -228,9 +340,11 @@ onLoad((options = {}) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(() => {
|
||||||
if (issue.value && issue.value.status === "issued" && tip.value.includes("绑定")) {
|
if (archiveBindPending.value && issue.value && issue.value.status === "issued") {
|
||||||
|
archiveBindPending.value = false;
|
||||||
autoPrompted.value = false;
|
autoPrompted.value = false;
|
||||||
promptClaim();
|
tip.value = "";
|
||||||
|
posterVisible.value = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -249,9 +363,13 @@ onShow(() => {
|
|||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poster-mask {
|
.poster-mask {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -264,6 +382,7 @@ onShow(() => {
|
|||||||
.poster-dialog {
|
.poster-dialog {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 620rpx;
|
max-width: 620rpx;
|
||||||
|
max-height: calc(100vh - 80rpx);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 20rpx;
|
border-radius: 20rpx;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
@ -272,15 +391,26 @@ onShow(() => {
|
|||||||
.poster-image {
|
.poster-image {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 58vh;
|
||||||
max-height: 700rpx;
|
max-height: 700rpx;
|
||||||
background: #f5f7fa;
|
background: #f5f7fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.poster-image--placeholder {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #9aa5b1;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.poster-content {
|
.poster-content {
|
||||||
padding: 28rpx 30rpx 8rpx;
|
padding: 28rpx 30rpx 8rpx;
|
||||||
color: #333;
|
color: #333;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
max-height: 160rpx;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poster-btn {
|
.poster-btn {
|
||||||
|
|||||||
@ -9,12 +9,13 @@
|
|||||||
>
|
>
|
||||||
<view class="page-body">
|
<view class="page-body">
|
||||||
<view v-if="loading" class="empty">加载中...</view>
|
<view v-if="loading" class="empty">加载中...</view>
|
||||||
<view v-else-if="!list.length" class="empty">暂无待领取体验券</view>
|
<view v-else-if="!list.length" class="empty">暂无体验券</view>
|
||||||
<view v-else class="coupon-list">
|
<view v-else class="coupon-list">
|
||||||
<view
|
<view
|
||||||
v-for="item in list"
|
v-for="item in list"
|
||||||
:key="item._id"
|
:key="item._id"
|
||||||
class="coupon-card"
|
class="coupon-card"
|
||||||
|
:class="item.cardClass"
|
||||||
@click="openPoster(item)"
|
@click="openPoster(item)"
|
||||||
>
|
>
|
||||||
<image
|
<image
|
||||||
@ -25,7 +26,14 @@
|
|||||||
/>
|
/>
|
||||||
<view v-else class="coupon-poster coupon-poster--empty">体验券</view>
|
<view v-else class="coupon-poster coupon-poster--empty">体验券</view>
|
||||||
<view class="coupon-body">
|
<view class="coupon-body">
|
||||||
|
<view class="coupon-title-row">
|
||||||
<view class="coupon-title">{{ item.activityName || "体验券" }}</view>
|
<view class="coupon-title">{{ item.activityName || "体验券" }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="coupon-state-row">
|
||||||
|
<view class="coupon-status" :class="item.statusClass">
|
||||||
|
{{ item.displayStatusText }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="coupon-info-grid">
|
<view class="coupon-info-grid">
|
||||||
<view class="coupon-info-row coupon-info-row--projects">
|
<view class="coupon-info-row coupon-info-row--projects">
|
||||||
<text class="coupon-info-label">项目</text>
|
<text class="coupon-info-label">项目</text>
|
||||||
@ -43,14 +51,20 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="coupon-info-row">
|
<view class="coupon-info-row">
|
||||||
<text class="coupon-info-label">项目有效期</text>
|
<text class="coupon-info-label">项目有效期</text>
|
||||||
<text>{{ item.validText }}</text>
|
<text>{{ item.projectValidText }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="coupon-info-row">
|
<view class="coupon-info-row">
|
||||||
<text class="coupon-info-label">活动有效期</text>
|
<text class="coupon-info-label">体验券有效期</text>
|
||||||
<text>{{ item.activityValidText }}</text>
|
<text>{{ item.couponValidText }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="coupon-info-row">
|
||||||
|
<text class="coupon-info-label">发送时间</text>
|
||||||
|
<text>{{ item.issueTimeText }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="coupon-action">点击查看海报领取</view>
|
<view class="coupon-action" :class="{ disabled: item.displayStatus !== 'issued' }">
|
||||||
|
{{ item.actionText }}
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -102,9 +116,18 @@ const posterVisible = ref(false);
|
|||||||
const current = ref(null);
|
const current = ref(null);
|
||||||
const claiming = ref(false);
|
const claiming = ref(false);
|
||||||
|
|
||||||
|
function toTimestamp(value) {
|
||||||
|
if (!value) return 0;
|
||||||
|
const numeric = Number(value);
|
||||||
|
if (Number.isFinite(numeric)) return numeric;
|
||||||
|
const parsed = new Date(value).getTime();
|
||||||
|
return Number.isNaN(parsed) ? 0 : parsed;
|
||||||
|
}
|
||||||
|
|
||||||
function formatDate(ts) {
|
function formatDate(ts) {
|
||||||
if (!ts) return "";
|
const time = toTimestamp(ts);
|
||||||
const d = new Date(Number(ts));
|
if (!time) return "";
|
||||||
|
const d = new Date(time);
|
||||||
if (Number.isNaN(d.getTime())) return "";
|
if (Number.isNaN(d.getTime())) return "";
|
||||||
const y = d.getFullYear();
|
const y = d.getFullYear();
|
||||||
const m = String(d.getMonth() + 1).padStart(2, "0");
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
||||||
@ -112,15 +135,26 @@ function formatDate(ts) {
|
|||||||
return `${y}-${m}-${day}`;
|
return `${y}-${m}-${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatDateTime(ts) {
|
||||||
|
const time = toTimestamp(ts);
|
||||||
|
if (!time) return "-";
|
||||||
|
const d = new Date(time);
|
||||||
|
if (Number.isNaN(d.getTime())) return "-";
|
||||||
|
const h = String(d.getHours()).padStart(2, "0");
|
||||||
|
const min = String(d.getMinutes()).padStart(2, "0");
|
||||||
|
return `${formatDate(time)} ${h}:${min}`;
|
||||||
|
}
|
||||||
|
|
||||||
function projectText(projects) {
|
function projectText(projects) {
|
||||||
const arr = Array.isArray(projects) ? projects : [];
|
const arr = Array.isArray(projects) ? projects : [];
|
||||||
if (!arr.length) return "未配置项目";
|
if (!arr.length) return "未配置项目";
|
||||||
return arr.map((p) => `${p.projectName || "项目"}×${p.usageCount || 1}`).join("、");
|
return arr.map((p) => `${p.projectName || "项目"}×${p.usageCount || 1}`).join("、");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildValidText(item) {
|
function buildProjectValidText(item) {
|
||||||
const rule = item.projectValidRuleSnapshot || {};
|
const rule = item.projectValidRuleSnapshot || {};
|
||||||
if (item.projectExpireTime) return `有效期至 ${formatDate(item.projectExpireTime)}`;
|
const projectExpireAt = toTimestamp(item.projectExpireTime);
|
||||||
|
if (projectExpireAt) return `有效期至 ${formatDate(projectExpireAt)}`;
|
||||||
if (rule.type === "fixedDate" && rule.fixedDate) {
|
if (rule.type === "fixedDate" && rule.fixedDate) {
|
||||||
return `有效期至 ${formatDate(rule.fixedDate)}`;
|
return `有效期至 ${formatDate(rule.fixedDate)}`;
|
||||||
}
|
}
|
||||||
@ -130,23 +164,20 @@ function buildValidText(item) {
|
|||||||
return "领取后按活动规则生效";
|
return "领取后按活动规则生效";
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildActivityValidText(item) {
|
function getCouponExpireAt(item) {
|
||||||
|
return toTimestamp(item.activityEndTime || item.displayExpireTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCouponValidText(item) {
|
||||||
const start = formatDate(item.activityStartTime) || "-";
|
const start = formatDate(item.activityStartTime) || "-";
|
||||||
const end = formatDate(item.activityEndTime) || "-";
|
const expireAt = getCouponExpireAt(item);
|
||||||
|
const end = formatDate(expireAt) || "-";
|
||||||
|
if (start === "-" && end === "-") return "未配置有效期";
|
||||||
return `${start} 至 ${end}`;
|
return `${start} 至 ${end}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExpireAt(item) {
|
|
||||||
if (item.projectExpireTime) return Number(item.projectExpireTime);
|
|
||||||
const rule = item.projectValidRuleSnapshot || {};
|
|
||||||
if (rule.type === "fixedDate" && rule.fixedDate) {
|
|
||||||
return Number(rule.fixedDate);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isExpired(item) {
|
function isExpired(item) {
|
||||||
const expireAt = getExpireAt(item);
|
const expireAt = getCouponExpireAt(item);
|
||||||
if (!expireAt) return false;
|
if (!expireAt) return false;
|
||||||
return Date.now() > expireAt;
|
return Date.now() > expireAt;
|
||||||
}
|
}
|
||||||
@ -184,20 +215,33 @@ async function resolveContext(options = {}) {
|
|||||||
return !!customerId.value;
|
return !!customerId.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function voidExpired(item) {
|
function resolveDisplayStatus(item) {
|
||||||
try {
|
const status = item.displayStatus || item.status || "issued";
|
||||||
await api(
|
if (status === "claimed") {
|
||||||
"voidExperienceCouponIssue",
|
return {
|
||||||
{
|
displayStatus: "claimed",
|
||||||
corpId: corpId.value,
|
displayStatusText: "已领取",
|
||||||
issueId: item._id,
|
actionText: "已领取",
|
||||||
voidReason: "有效期内未领取,自动失效",
|
cardClass: "coupon-card--claimed",
|
||||||
},
|
statusClass: "coupon-status--claimed",
|
||||||
false
|
};
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("auto void failed", e);
|
|
||||||
}
|
}
|
||||||
|
if (status === "expired" || status === "void" || isExpired(item)) {
|
||||||
|
return {
|
||||||
|
displayStatus: "expired",
|
||||||
|
displayStatusText: "已过期",
|
||||||
|
actionText: "已过期",
|
||||||
|
cardClass: "coupon-card--expired",
|
||||||
|
statusClass: "coupon-status--expired",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
displayStatus: "issued",
|
||||||
|
displayStatusText: "待领取",
|
||||||
|
actionText: "点击查看海报领取",
|
||||||
|
cardClass: "coupon-card--issued",
|
||||||
|
statusClass: "coupon-status--issued",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadCoupons(options = {}) {
|
async function loadCoupons(options = {}) {
|
||||||
@ -213,7 +257,6 @@ async function loadCoupons(options = {}) {
|
|||||||
{
|
{
|
||||||
corpId: corpId.value,
|
corpId: corpId.value,
|
||||||
customerId: customerId.value,
|
customerId: customerId.value,
|
||||||
status: "issued",
|
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 100,
|
pageSize: 100,
|
||||||
},
|
},
|
||||||
@ -225,20 +268,19 @@ async function loadCoupons(options = {}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const raw = res.list || res.data?.list || [];
|
const raw = res.list || res.data?.list || [];
|
||||||
const valid = [];
|
list.value = raw
|
||||||
for (const item of raw) {
|
.map((item) => {
|
||||||
if (isExpired(item)) {
|
const status = resolveDisplayStatus(item);
|
||||||
voidExpired(item);
|
return {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
valid.push({
|
|
||||||
...item,
|
...item,
|
||||||
|
...status,
|
||||||
projectText: projectText(item.projectSnapshot),
|
projectText: projectText(item.projectSnapshot),
|
||||||
validText: buildValidText(item),
|
projectValidText: buildProjectValidText(item),
|
||||||
activityValidText: buildActivityValidText(item),
|
couponValidText: buildCouponValidText(item),
|
||||||
});
|
issueTimeText: formatDateTime(item.issueTime || item.createTime),
|
||||||
}
|
};
|
||||||
list.value = valid;
|
})
|
||||||
|
.sort((a, b) => Number(b.issueTime || b.createTime || 0) - Number(a.issueTime || a.createTime || 0));
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
@ -255,6 +297,10 @@ async function refreshCoupons() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openPoster(item) {
|
function openPoster(item) {
|
||||||
|
if (item?.displayStatus !== "issued") {
|
||||||
|
toast(item?.displayStatusText || "当前体验券不可领取");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!item?.posterUrl) {
|
if (!item?.posterUrl) {
|
||||||
toast("该体验券暂无海报");
|
toast("该体验券暂无海报");
|
||||||
return;
|
return;
|
||||||
@ -338,6 +384,11 @@ onShow(async () => {
|
|||||||
box-shadow: 0 8rpx 10rpx 0 rgba(60, 169, 145, 0.06);
|
box-shadow: 0 8rpx 10rpx 0 rgba(60, 169, 145, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coupon-card--claimed,
|
||||||
|
.coupon-card--expired {
|
||||||
|
opacity: 0.78;
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-poster {
|
.coupon-poster {
|
||||||
width: 160rpx;
|
width: 160rpx;
|
||||||
height: 160rpx;
|
height: 160rpx;
|
||||||
@ -359,11 +410,48 @@ onShow(async () => {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coupon-title-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16rpx;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-state-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.coupon-title {
|
.coupon-title {
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #222;
|
color: #222;
|
||||||
margin-bottom: 8rpx;
|
}
|
||||||
|
|
||||||
|
.coupon-status {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 4rpx 12rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-status--issued {
|
||||||
|
color: #ff8a00;
|
||||||
|
background: rgba(255, 138, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-status--claimed {
|
||||||
|
color: #0f766e;
|
||||||
|
background: rgba(15, 118, 110, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.coupon-status--expired {
|
||||||
|
color: #909399;
|
||||||
|
background: #f0f2f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.coupon-info-grid {
|
.coupon-info-grid {
|
||||||
@ -416,6 +504,10 @@ onShow(async () => {
|
|||||||
color: #ff8a00;
|
color: #ff8a00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.coupon-action.disabled {
|
||||||
|
color: #a8abb2;
|
||||||
|
}
|
||||||
|
|
||||||
.empty {
|
.empty {
|
||||||
padding: 120rpx 0;
|
padding: 120rpx 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@ -86,8 +86,14 @@ function formatDate(ts) {
|
|||||||
return `${y}-${m}-${day}`;
|
return `${y}-${m}-${day}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickCorpName(team = {}) {
|
async function loadCorpName() {
|
||||||
return team.licenseHospitalName || team.leaderCorp || team.corpName || "-";
|
if (!corpId.value) {
|
||||||
|
corpName.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await api("getCorpInfo", { corpId: corpId.value }, false);
|
||||||
|
const corp = Array.isArray(res?.data) ? res.data[0] : null;
|
||||||
|
corpName.value = corp?.corp_name || corp?.corpName || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const groups = computed(() => {
|
const groups = computed(() => {
|
||||||
@ -139,16 +145,6 @@ function applySelection(selection = {}) {
|
|||||||
teamId.value = selection.teamId || teamId.value || "";
|
teamId.value = selection.teamId || teamId.value || "";
|
||||||
customerId.value = selection.customerId || selection.memberId || customerId.value || "";
|
customerId.value = selection.customerId || selection.memberId || customerId.value || "";
|
||||||
customerName.value = selection.name || customerName.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 = {}) {
|
async function resolveContext(options = {}) {
|
||||||
@ -181,7 +177,7 @@ async function resolveContext(options = {}) {
|
|||||||
|
|
||||||
if (!corpId.value) corpId.value = normalizeCorpId(matched?.corpId || "");
|
if (!corpId.value) corpId.value = normalizeCorpId(matched?.corpId || "");
|
||||||
if (!teamId.value) teamId.value = matched?.teamId || "";
|
if (!teamId.value) teamId.value = matched?.teamId || "";
|
||||||
if (!corpName.value) corpName.value = pickCorpName(matched || {});
|
await loadCorpName();
|
||||||
|
|
||||||
if (customerId.value) return true;
|
if (customerId.value) return true;
|
||||||
|
|
||||||
@ -240,6 +236,7 @@ async function syncSelectedProfile() {
|
|||||||
if (!selected) return false;
|
if (!selected) return false;
|
||||||
remove(RIGHTS_SELECTION_CACHE_KEY);
|
remove(RIGHTS_SELECTION_CACHE_KEY);
|
||||||
applySelection(selected);
|
applySelection(selected);
|
||||||
|
await loadCorpName();
|
||||||
await loadRights();
|
await loadRights();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
<view class="page-body">
|
<view class="page-body">
|
||||||
<view v-if="loading" class="empty">加载中...</view>
|
<view v-if="loading" class="empty">加载中...</view>
|
||||||
<view v-else-if="!options.length" class="empty">暂无可用档案</view>
|
<view v-else-if="!options.length" class="empty">暂无可用档案</view>
|
||||||
<view v-else class="archive-list">
|
<scroll-view v-else scroll-y class="archive-list">
|
||||||
<view
|
<view
|
||||||
v-for="item in options"
|
v-for="item in options"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
@ -22,7 +22,7 @@
|
|||||||
<view class="archive-id">证件号:{{ item.idCardText }}</view>
|
<view class="archive-id">证件号:{{ item.idCardText }}</view>
|
||||||
<view class="archive-corp">{{ item.corpName }}</view>
|
<view class="archive-corp">{{ item.corpName }}</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</full-page>
|
</full-page>
|
||||||
</template>
|
</template>
|
||||||
@ -33,14 +33,14 @@ import { onLoad } from "@dcloudio/uni-app";
|
|||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from "pinia";
|
||||||
import useAccount from "@/store/account";
|
import useAccount from "@/store/account";
|
||||||
import api from "@/utils/api";
|
import api from "@/utils/api";
|
||||||
import { set } from "@/utils/cache";
|
import { get, set } from "@/utils/cache";
|
||||||
import { toast } from "@/utils/widget";
|
import { toast } from "@/utils/widget";
|
||||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||||
import FullPage from "@/components/full-page.vue";
|
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 RIGHTS_SELECTION_CACHE_KEY = "experience-coupon-rights-selection";
|
||||||
const { account } = storeToRefs(useAccount());
|
const { account } = storeToRefs(useAccount());
|
||||||
const { getTeams } = useAccount();
|
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const options = ref([]);
|
const options = ref([]);
|
||||||
@ -50,10 +50,6 @@ const currentCustomerId = ref("");
|
|||||||
const mode = ref("back");
|
const mode = ref("back");
|
||||||
const target = ref("");
|
const target = ref("");
|
||||||
|
|
||||||
function pickCorpName(team = {}) {
|
|
||||||
return team.licenseHospitalName || team.leaderCorp || team.corpName || "-";
|
|
||||||
}
|
|
||||||
|
|
||||||
function maskMobile(mobile = "") {
|
function maskMobile(mobile = "") {
|
||||||
const value = String(mobile || "").trim();
|
const value = String(mobile || "").trim();
|
||||||
if (!value) return "";
|
if (!value) return "";
|
||||||
@ -77,16 +73,6 @@ function buildMetaText(customer = {}) {
|
|||||||
return parts.length ? parts.join(",") : "暂无档案信息";
|
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) {
|
function buildTargetUrl(item) {
|
||||||
const corp = encodeURIComponent(item.corpId || "");
|
const corp = encodeURIComponent(item.corpId || "");
|
||||||
const team = encodeURIComponent(item.teamId || "");
|
const team = encodeURIComponent(item.teamId || "");
|
||||||
@ -119,35 +105,34 @@ async function loadArchives() {
|
|||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const teams = (await getTeams()) || [];
|
const currentTeam = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
|
||||||
const corpTeams = dedupeByCorp(teams);
|
const selectedCorpId = normalizeCorpId(currentTeam.corpId || currentCorpId.value);
|
||||||
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
|
if (!selectedCorpId) {
|
||||||
.flat()
|
options.value = [];
|
||||||
.map(({ team, customer }) => ({
|
return;
|
||||||
key: `${team.corpId}_${customer._id}`,
|
}
|
||||||
corpId: team.corpId,
|
|
||||||
teamId: team.teamId || "",
|
const [corpRes, customerRes] = await Promise.all([
|
||||||
|
api("getCorpInfo", { corpId: selectedCorpId }, false),
|
||||||
|
api("getCorpMiniAppCustomers", { miniAppId, corpId: selectedCorpId }, false),
|
||||||
|
]);
|
||||||
|
const corp = Array.isArray(corpRes?.data) ? corpRes.data[0] : null;
|
||||||
|
const archiveCorpName = corp?.corp_name || corp?.corpName || "-";
|
||||||
|
const customers = customerRes?.success && Array.isArray(customerRes.data) ? customerRes.data : [];
|
||||||
|
const list = customers
|
||||||
|
.map((customer) => ({
|
||||||
|
key: `${selectedCorpId}_${customer._id}`,
|
||||||
|
corpId: selectedCorpId,
|
||||||
|
teamId: currentTeam.teamId || currentTeamId.value || "",
|
||||||
customerId: customer._id || "",
|
customerId: customer._id || "",
|
||||||
name: customer.name || "",
|
name: customer.name || "",
|
||||||
relationship: customer.relationship || "",
|
relationship: customer.relationship || "",
|
||||||
metaText: buildMetaText(customer),
|
metaText: buildMetaText(customer),
|
||||||
idCardText: maskIdCard(customer.idCard),
|
idCardText: maskIdCard(customer.idCard),
|
||||||
corpName: pickCorpName(team),
|
corpName: archiveCorpName,
|
||||||
}))
|
}))
|
||||||
.filter((item) => item.corpId && item.customerId)
|
.filter((item) => item.customerId)
|
||||||
.sort((a, b) => {
|
.sort((a, b) => {
|
||||||
const aScore =
|
const aScore =
|
||||||
(a.corpId === currentCorpId.value ? 4 : 0) +
|
(a.corpId === currentCorpId.value ? 4 : 0) +
|
||||||
@ -210,12 +195,16 @@ onLoad(async (optionsData = {}) => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.page-body {
|
.page-body {
|
||||||
min-height: 100%;
|
height: 100vh;
|
||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: #f5f6fa;
|
background: #f5f6fa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.archive-list {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.archive-card {
|
.archive-card {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 18rpx;
|
border-radius: 18rpx;
|
||||||
|
|||||||
@ -48,6 +48,7 @@ import pageLoading from "./loading.vue";
|
|||||||
const { account } = storeToRefs(useAccount());
|
const { account } = storeToRefs(useAccount());
|
||||||
const { login, getTeams } = useAccount();
|
const { login, getTeams } = useAccount();
|
||||||
const env = __VITE_ENV__;
|
const env = __VITE_ENV__;
|
||||||
|
const appid = env.MP_WX_APP_ID;
|
||||||
const shareAppVersion = env.MP_SHARE_WX_APP_VERSION;
|
const shareAppVersion = env.MP_SHARE_WX_APP_VERSION;
|
||||||
|
|
||||||
const team = ref(null);
|
const team = ref(null);
|
||||||
@ -58,6 +59,8 @@ const consultRef = ref(null);
|
|||||||
const archiveRef = ref(null);
|
const archiveRef = ref(null);
|
||||||
const corpUserIds = ref({});
|
const corpUserIds = ref({});
|
||||||
const referenceCustomerIds = ref({});
|
const referenceCustomerIds = ref({});
|
||||||
|
const pendingAction = ref(null);
|
||||||
|
const awaitingArchiveBinding = ref(false);
|
||||||
const HOME_CURRENT_TEAM_CACHE_KEY = "home-current-team-info";
|
const HOME_CURRENT_TEAM_CACHE_KEY = "home-current-team-info";
|
||||||
|
|
||||||
const corpId = computed(() => team.value?.corpId);
|
const corpId = computed(() => team.value?.corpId);
|
||||||
@ -84,7 +87,7 @@ function cacheCurrentTeam(currentTeam) {
|
|||||||
|
|
||||||
function isSameTeam(candidate, target = {}) {
|
function isSameTeam(candidate, target = {}) {
|
||||||
const targetTeamId = target.teamId || "";
|
const targetTeamId = target.teamId || "";
|
||||||
if (!candidate || !candidate.teamId || candidate.teamId !== targetTeamId) return false;
|
if (!candidate || !candidate.teamId || String(candidate.teamId) !== String(targetTeamId)) return false;
|
||||||
|
|
||||||
const targetCorpId = normalizeCorpId(target.corpId || "");
|
const targetCorpId = normalizeCorpId(target.corpId || "");
|
||||||
if (!targetCorpId) return true;
|
if (!targetCorpId) return true;
|
||||||
@ -95,22 +98,136 @@ function isSameTeam(candidate, target = {}) {
|
|||||||
|
|
||||||
async function changeTeam({ teamId, corpId, corpName }) {
|
async function changeTeam({ teamId, corpId, corpName }) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await api("getTeamData", { teamId, corpId });
|
try {
|
||||||
loading.value = false;
|
const res = await api("getTeamData", { teamId, corpId, withCorpName: true });
|
||||||
if (res && res.data) {
|
if (res && res.data) {
|
||||||
team.value = {
|
team.value = {
|
||||||
...res.data,
|
...res.data,
|
||||||
corpId: normalizeCorpId(res.data.corpId || corpId),
|
corpId: normalizeCorpId(res.data.corpId || corpId),
|
||||||
};
|
};
|
||||||
team.value.corpName = corpName;
|
team.value.corpName = corpName || res.data.corpName || res.data.corp_name || "";
|
||||||
cacheCurrentTeam(team.value);
|
cacheCurrentTeam(team.value);
|
||||||
} else {
|
return team.value;
|
||||||
toast(res?.message || "获取团队信息失败");
|
|
||||||
}
|
}
|
||||||
|
toast(res?.message || "获取团队信息失败");
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parsePendingAction(options = {}) {
|
||||||
|
const type = options.type || "";
|
||||||
|
if (type === "experienceCoupon" && options.issueId && options.corpId) {
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
corpId: normalizeCorpId(options.corpId),
|
||||||
|
teamId: options.teamId || "",
|
||||||
|
issueId: options.issueId,
|
||||||
|
memberId: options.memberId || options.customerId || "",
|
||||||
|
couponId: options.couponId || "",
|
||||||
|
unionid: options.unionid || "",
|
||||||
|
externalUserId: options.externalUserId || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (type === "appointmentRegistration" && options.customerId && options.corpId) {
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
corpId: normalizeCorpId(options.corpId),
|
||||||
|
teamId: options.teamId || "",
|
||||||
|
customerId: options.customerId,
|
||||||
|
name: options.name || "",
|
||||||
|
corpName: options.corpName || "",
|
||||||
|
appointmentId: options.appointmentId || "",
|
||||||
|
month: options.month || "",
|
||||||
|
externalUserId: options.externalUserId || "",
|
||||||
|
corpUserId: options.corpUserId || "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildActionUrl(action) {
|
||||||
|
const params = Object.entries(action)
|
||||||
|
.filter(([key, value]) => key !== "type" && value)
|
||||||
|
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
||||||
|
.join("&");
|
||||||
|
const page = action.type === "experienceCoupon"
|
||||||
|
? "/pages/experience-coupon/claim"
|
||||||
|
: "/pages/record/appointment-record";
|
||||||
|
return `${page}?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildArchiveBindUrl(action) {
|
||||||
|
const customerId = action.memberId || action.customerId;
|
||||||
|
return [
|
||||||
|
`/pages/archive/edit-archive?corpId=${encodeURIComponent(action.corpId)}`,
|
||||||
|
`teamId=${encodeURIComponent(team.value?.teamId || action.teamId)}`,
|
||||||
|
`bindCustomerId=${encodeURIComponent(customerId)}`,
|
||||||
|
`source=${encodeURIComponent(action.type)}`,
|
||||||
|
].join("&");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function syncPendingExternalUser(action) {
|
||||||
|
if (!action?.externalUserId || !account.value?.openid || !action.corpId) return;
|
||||||
|
try {
|
||||||
|
await api("syncWxappExternalUserRelation", {
|
||||||
|
corpId: action.corpId,
|
||||||
|
externalUserId: action.externalUserId,
|
||||||
|
unionid: action.unionid || account.value.unionid || "",
|
||||||
|
openid: account.value.openid,
|
||||||
|
corpUserId: action.corpUserId || "",
|
||||||
|
}, false);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("同步外部联系人关系失败", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function continuePendingAction() {
|
||||||
|
const action = pendingAction.value;
|
||||||
|
if (!action || !account.value?.openid || !team.value?.teamId) return;
|
||||||
|
|
||||||
|
if (action.teamId && String(action.teamId) !== String(team.value.teamId)) {
|
||||||
|
toast("未找到目标服务团队");
|
||||||
|
pendingAction.value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await syncPendingExternalUser(action);
|
||||||
|
|
||||||
|
const customerId = action.memberId || action.customerId;
|
||||||
|
const customerRes = await api(
|
||||||
|
"getCustomerByCustomerId",
|
||||||
|
{ corpId: action.corpId, customerId },
|
||||||
|
false
|
||||||
|
);
|
||||||
|
const customer = customerRes?.data || null;
|
||||||
|
if (!customer) {
|
||||||
|
toast(customerRes?.message || "目标档案不存在");
|
||||||
|
pendingAction.value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const archiveBound = String(customer.miniAppId || "") === String(account.value.openid);
|
||||||
|
if (!archiveBound) {
|
||||||
|
if (awaitingArchiveBinding.value) {
|
||||||
|
awaitingArchiveBinding.value = false;
|
||||||
|
pendingAction.value = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
awaitingArchiveBinding.value = true;
|
||||||
|
uni.navigateTo({ url: buildArchiveBindUrl(action) });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingAction.value = null;
|
||||||
|
awaitingArchiveBinding.value = false;
|
||||||
|
uni.navigateTo({ url: buildActionUrl(action) });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMatchTeams(inviteTeam = null) {
|
async function getMatchTeams(inviteTeam = null) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
try {
|
||||||
teams.value = await getTeams();
|
teams.value = await getTeams();
|
||||||
const inviteIdentity = typeof inviteTeam === "string" ? { teamId: inviteTeam } : (inviteTeam || {});
|
const inviteIdentity = typeof inviteTeam === "string" ? { teamId: inviteTeam } : (inviteTeam || {});
|
||||||
const cachedIdentity = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
|
const cachedIdentity = get(HOME_CURRENT_TEAM_CACHE_KEY) || {};
|
||||||
@ -118,14 +235,46 @@ async function getMatchTeams(inviteTeam = null) {
|
|||||||
teamId: inviteIdentity.teamId || team.value?.teamId || cachedIdentity.teamId,
|
teamId: inviteIdentity.teamId || team.value?.teamId || cachedIdentity.teamId,
|
||||||
corpId: inviteIdentity.corpId || team.value?.corpId || cachedIdentity.corpId,
|
corpId: inviteIdentity.corpId || team.value?.corpId || cachedIdentity.corpId,
|
||||||
});
|
});
|
||||||
const validTeam = teams.value.find(i => isSameTeam(i, targetIdentity));
|
let validTeam = teams.value.find(i => isSameTeam(i, targetIdentity));
|
||||||
const firstTeam = teams.value[0]
|
|
||||||
if (validTeam || firstTeam) {
|
if (pendingAction.value && targetIdentity.teamId && account.value?.openid) {
|
||||||
changeTeam(validTeam || firstTeam);
|
if (!validTeam) {
|
||||||
} else {
|
const bindRes = await api("bindWxappWithTeam", {
|
||||||
|
appid,
|
||||||
|
corpId: targetIdentity.corpId,
|
||||||
|
teamId: targetIdentity.teamId,
|
||||||
|
openid: account.value.openid,
|
||||||
|
});
|
||||||
|
if (!bindRes?.success) {
|
||||||
|
toast(bindRes?.message || "关联医生团队失败");
|
||||||
team.value = null;
|
team.value = null;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
teams.value = await getTeams();
|
||||||
|
validTeam = teams.value.find(i => isSameTeam(i, targetIdentity));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 链接中的团队是本次动作的作用域,即使用户已绑定多个团队,也必须切换到该团队。
|
||||||
|
const targetTeam = await changeTeam({
|
||||||
|
...targetIdentity,
|
||||||
|
corpName: validTeam?.corpName || "",
|
||||||
|
});
|
||||||
|
if (targetTeam) {
|
||||||
|
teams.value = teams.value.length ? teams.value : [targetTeam];
|
||||||
|
return targetTeam;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstTeam = teams.value[0];
|
||||||
|
if (validTeam || firstTeam) {
|
||||||
|
return await changeTeam(validTeam || firstTeam);
|
||||||
|
}
|
||||||
|
team.value = null;
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// useLoad((opts) => {
|
// useLoad((opts) => {
|
||||||
@ -134,8 +283,8 @@ async function getMatchTeams(inviteTeam = null) {
|
|||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
onLoad(() => {
|
onLoad((options = {}) => {
|
||||||
if (!account.value) login();
|
pendingAction.value = parsePendingAction(options);
|
||||||
})
|
})
|
||||||
|
|
||||||
onShow(async () => {
|
onShow(async () => {
|
||||||
@ -149,7 +298,11 @@ onShow(async () => {
|
|||||||
referenceCustomerIds.value[inviteTeam.teamId] = inviteTeam.referenceCustomerId;
|
referenceCustomerIds.value[inviteTeam.teamId] = inviteTeam.referenceCustomerId;
|
||||||
}
|
}
|
||||||
if (account.value && account.value.openid) {
|
if (account.value && account.value.openid) {
|
||||||
getMatchTeams(inviteTeam && inviteTeam.teamId ? inviteTeam : null);
|
const targetTeam = pendingAction.value?.teamId
|
||||||
|
? { teamId: pendingAction.value.teamId, corpId: pendingAction.value.corpId }
|
||||||
|
: null;
|
||||||
|
await getMatchTeams(targetTeam || (inviteTeam && inviteTeam.teamId ? inviteTeam : null));
|
||||||
|
await continuePendingAction();
|
||||||
} else {
|
} else {
|
||||||
teams.value = [];
|
teams.value = [];
|
||||||
}
|
}
|
||||||
@ -161,7 +314,7 @@ onShow(async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onShareAppMessage((res) => {
|
onShareAppMessage(() => {
|
||||||
if (team.value && team.value.supportPatientForward === 'YES') {
|
if (team.value && team.value.supportPatientForward === 'YES') {
|
||||||
const customer = customers.value[0];
|
const customer = customers.value[0];
|
||||||
const referenceCustomerId = customer ? customer._id : '';
|
const referenceCustomerId = customer ? customer._id : '';
|
||||||
@ -173,9 +326,9 @@ onShareAppMessage((res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(account, (n, o) => {
|
watch(account, async (n, o) => {
|
||||||
if (n && !o) {
|
if (n && !o) {
|
||||||
getMatchTeams();
|
if (!pendingAction.value) await getMatchTeams();
|
||||||
} else if (!n && o) {
|
} else if (!n && o) {
|
||||||
teams.value = [];
|
teams.value = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,10 +133,12 @@ async function bindTeam() {
|
|||||||
}
|
}
|
||||||
await syncExternalUserRelation();
|
await syncExternalUserRelation();
|
||||||
const res1 = await api('getWxAppCustomerCount', { miniAppId: account.value.openid, corpId: team.value.corpId, teamId: team.value.teamId });
|
const res1 = await api('getWxAppCustomerCount', { miniAppId: account.value.openid, corpId: team.value.corpId, teamId: team.value.teamId });
|
||||||
if (res1 && res1.data > 0) {
|
if (redirectUrl.value) {
|
||||||
|
await attempToPage(redirectUrl.value)
|
||||||
|
} else if (res1 && res1.data > 0) {
|
||||||
toHome();
|
toHome();
|
||||||
} else {
|
} else {
|
||||||
attempToPage(redirectUrl.value)
|
attempToPage(`/pages/archive/edit-archive?corpUserId=${team.value.corpUserId || ''}&teamId=${team.value.teamId}&corpId=${team.value.corpId}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +149,7 @@ async function getPhoneNumber(e) {
|
|||||||
if (!res) return;
|
if (!res) return;
|
||||||
}
|
}
|
||||||
if (team.value) {
|
if (team.value) {
|
||||||
bindTeam()
|
await bindTeam()
|
||||||
} else if (redirectUrl.value) {
|
} else if (redirectUrl.value) {
|
||||||
await attempToPage(redirectUrl.value);
|
await attempToPage(redirectUrl.value);
|
||||||
} else {
|
} else {
|
||||||
@ -156,20 +158,33 @@ async function getPhoneNumber(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function attempToPage(url) {
|
async function attempToPage(url) {
|
||||||
const res1 = attempRedirect(url);
|
if (!url) {
|
||||||
if (res1) return;
|
|
||||||
const res2 = attempSwitchTab(url);
|
|
||||||
if (res2) return;
|
|
||||||
toHome();
|
toHome();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await attempRedirect(url);
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
// redirectTo 不支持 tabBar 时再尝试 switchTab。
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await attempSwitchTab(url);
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
toHome();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad((opts) => {
|
onLoad((opts) => {
|
||||||
|
redirectUrl.value = opts.redirectUrl || "";
|
||||||
if (opts.source === "teamInvite") {
|
if (opts.source === "teamInvite") {
|
||||||
team.value = get("invite-team-info");
|
team.value = get("invite-team-info");
|
||||||
|
if (!redirectUrl.value && team.value) {
|
||||||
redirectUrl.value = `/pages/archive/edit-archive?corpUserId=${team.value.corpUserId || ''}&teamId=${team.value.teamId}&corpId=${team.value.corpId}`;
|
redirectUrl.value = `/pages/archive/edit-archive?corpUserId=${team.value.corpUserId || ''}&teamId=${team.value.teamId}&corpId=${team.value.corpId}`;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
redirectUrl.value = opts.redirectUrl || "";
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@ -143,24 +143,47 @@ async function bindTeam({ corpUserId, externalUserId }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePlainOptions(options = {}) {
|
||||||
|
return Object.keys(options || {}).reduce((acc, key) => {
|
||||||
|
acc[key] = typeof options[key] === 'string' ? safeDecode(options[key]) : options[key];
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
|
|
||||||
onLoad((options) => {
|
onLoad((options) => {
|
||||||
if (options.q) {
|
const normalizedOptions = normalizePlainOptions(options);
|
||||||
opts.value = JSON.stringify(options)
|
if (normalizedOptions.q) {
|
||||||
changeTeam(parseInviteOptions(options));
|
opts.value = JSON.stringify(normalizedOptions)
|
||||||
} else if (options.type === 'experienceCoupon' && options.issueId && options.corpId) {
|
changeTeam(parseInviteOptions(normalizedOptions));
|
||||||
|
} else if (normalizedOptions.type === 'experienceCoupon' && normalizedOptions.issueId && normalizedOptions.corpId) {
|
||||||
const params = [
|
const params = [
|
||||||
`corpId=${encodeURIComponent(options.corpId || "")}`,
|
`corpId=${encodeURIComponent(normalizedOptions.corpId || "")}`,
|
||||||
`issueId=${encodeURIComponent(options.issueId || "")}`,
|
`issueId=${encodeURIComponent(normalizedOptions.issueId || "")}`,
|
||||||
options.memberId ? `memberId=${encodeURIComponent(options.memberId)}` : "",
|
normalizedOptions.memberId ? `memberId=${encodeURIComponent(normalizedOptions.memberId)}` : "",
|
||||||
options.couponId ? `couponId=${encodeURIComponent(options.couponId)}` : "",
|
normalizedOptions.couponId ? `couponId=${encodeURIComponent(normalizedOptions.couponId)}` : "",
|
||||||
options.unionid ? `unionid=${encodeURIComponent(options.unionid)}` : "",
|
normalizedOptions.unionid ? `unionid=${encodeURIComponent(normalizedOptions.unionid)}` : "",
|
||||||
options.externalUserId ? `externalUserId=${encodeURIComponent(options.externalUserId)}` : "",
|
normalizedOptions.externalUserId ? `externalUserId=${encodeURIComponent(normalizedOptions.externalUserId)}` : "",
|
||||||
].filter(Boolean).join("&");
|
].filter(Boolean).join("&");
|
||||||
uni.redirectTo({
|
uni.redirectTo({
|
||||||
url: `/pages/experience-coupon/claim?${params}`,
|
url: `/pages/experience-coupon/claim?${params}`,
|
||||||
});
|
});
|
||||||
} else if (options.type === 'archive' || (options.teamId && options.corpId)) {
|
} else if (normalizedOptions.type === 'appointmentRegistration' && normalizedOptions.customerId && normalizedOptions.corpId) {
|
||||||
changeTeam(options);
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(normalizedOptions.corpId || "")}`,
|
||||||
|
normalizedOptions.teamId ? `teamId=${encodeURIComponent(normalizedOptions.teamId)}` : "",
|
||||||
|
`customerId=${encodeURIComponent(normalizedOptions.customerId || "")}`,
|
||||||
|
normalizedOptions.name ? `name=${encodeURIComponent(normalizedOptions.name)}` : "",
|
||||||
|
normalizedOptions.corpName ? `corpName=${encodeURIComponent(normalizedOptions.corpName)}` : "",
|
||||||
|
normalizedOptions.appointmentId ? `appointmentId=${encodeURIComponent(normalizedOptions.appointmentId)}` : "",
|
||||||
|
normalizedOptions.month ? `month=${encodeURIComponent(normalizedOptions.month)}` : "",
|
||||||
|
normalizedOptions.externalUserId ? `externalUserId=${encodeURIComponent(normalizedOptions.externalUserId)}` : "",
|
||||||
|
normalizedOptions.corpUserId ? `corpUserId=${encodeURIComponent(normalizedOptions.corpUserId)}` : "",
|
||||||
|
].filter(Boolean).join("&");
|
||||||
|
uni.redirectTo({
|
||||||
|
url: `/pages/record/appointment-record?${params}`,
|
||||||
|
});
|
||||||
|
} else if (normalizedOptions.type === 'archive' || (normalizedOptions.teamId && normalizedOptions.corpId)) {
|
||||||
|
changeTeam(normalizedOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1231,6 +1231,25 @@ $primary-color: #0877F1;
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-bubble,
|
||||||
|
.benefit-bubble {
|
||||||
|
padding: 0 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-bubble::before,
|
||||||
|
.custom-bubble::after,
|
||||||
|
.benefit-bubble::before,
|
||||||
|
.benefit-bubble::after {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-bubble {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.message-right .message-card {
|
.message-right .message-card {
|
||||||
margin-right: 8rpx;
|
margin-right: 8rpx;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,28 @@
|
|||||||
mode="aspectFill" />
|
mode="aspectFill" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 权益消息 -->
|
||||||
|
<view v-else-if="getCustomMessageType(message) === 'benefit'" class="benefit-card">
|
||||||
|
<view class="benefit-title">{{ benefitData.title }}</view>
|
||||||
|
<view class="benefit-content">
|
||||||
|
<view v-for="(item, index) in benefitData.items" :key="`${item.projectId}-${index}`" class="benefit-item">
|
||||||
|
<view class="benefit-project-row">
|
||||||
|
<text v-if="index === 0" class="benefit-label">项目:</text>
|
||||||
|
<text v-else class="benefit-label-placeholder"></text>
|
||||||
|
<text class="benefit-project-name">{{ item.projectName }}</text>
|
||||||
|
<text class="benefit-count">X{{ item.usageCount }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="benefit-valid-row">
|
||||||
|
<text class="benefit-valid-label">有效期:</text>
|
||||||
|
<text class="benefit-valid-value">{{ item.validTimeText || '无限期' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="benefit-detail-button" @click.stop="handleBenefitClick">
|
||||||
|
<text class="benefit-detail-text">查看详情</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 其他自定义消息 -->
|
<!-- 其他自定义消息 -->
|
||||||
<!-- <view
|
<!-- <view
|
||||||
v-else
|
v-else
|
||||||
@ -112,8 +134,32 @@ const payloadData = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const benefitData = computed(() => ({
|
||||||
|
title: payloadData.value.title || "医生为您录入专属权益",
|
||||||
|
patientId: payloadData.value.patientId || "",
|
||||||
|
patientName: payloadData.value.patientName || "",
|
||||||
|
corpId: payloadData.value.corpId || props.corpId || "",
|
||||||
|
teamId: payloadData.value.teamId || "",
|
||||||
|
items: Array.isArray(payloadData.value.items) ? payloadData.value.items : [],
|
||||||
|
}))
|
||||||
|
|
||||||
// 计算图片样式
|
const handleBenefitClick = () => {
|
||||||
|
const customerId = benefitData.value.patientId;
|
||||||
|
const corpId = benefitData.value.corpId;
|
||||||
|
if (!customerId || !corpId) {
|
||||||
|
toast("权益信息不完整");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(corpId)}`,
|
||||||
|
`teamId=${encodeURIComponent(benefitData.value.teamId || "")}`,
|
||||||
|
`customerId=${encodeURIComponent(customerId)}`,
|
||||||
|
`name=${encodeURIComponent(benefitData.value.patientName || "")}`,
|
||||||
|
].join("&");
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/experience-coupon/my-rights?${params}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
const getImageStyle = (imageInfo) => {
|
const getImageStyle = (imageInfo) => {
|
||||||
// 如果没有尺寸信息,使用默认样式
|
// 如果没有尺寸信息,使用默认样式
|
||||||
imageInfo.width = imageInfo.width || imageInfo.Width;
|
imageInfo.width = imageInfo.width || imageInfo.Width;
|
||||||
@ -299,4 +345,95 @@ async function markArticleRead(sendId, articleId) {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "../chat.scss";
|
@import "../chat.scss";
|
||||||
|
|
||||||
|
.benefit-card {
|
||||||
|
width: 520rpx;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
padding: 22rpx 18rpx 18rpx;
|
||||||
|
background: linear-gradient(180deg, #0b75f2 0%, #0067df 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-title {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
margin-bottom: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-content {
|
||||||
|
border: 4rpx solid rgba(255, 255, 255, 0.28);
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 24rpx 24rpx 28rpx;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-item + .benefit-item {
|
||||||
|
margin-top: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-project-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-label,
|
||||||
|
.benefit-label-placeholder {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 104rpx;
|
||||||
|
color: #8b8f96;
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-project-name {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
color: #111827;
|
||||||
|
font-size: 30rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-count {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 16rpx;
|
||||||
|
color: #111827;
|
||||||
|
font-size: 30rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-valid-row {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 104rpx;
|
||||||
|
margin-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-valid-label,
|
||||||
|
.benefit-valid-value {
|
||||||
|
color: #8b8f96;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-detail-button {
|
||||||
|
height: 82rpx;
|
||||||
|
margin-top: 28rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: linear-gradient(180deg, #0b75f2 0%, #0067df 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.benefit-detail-text {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -390,6 +390,19 @@ function handleSystemMessageReceived(message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取自定义消息类型
|
||||||
|
function getCustomMessageType(message) {
|
||||||
|
try {
|
||||||
|
const data =
|
||||||
|
typeof message.payload?.data === "string"
|
||||||
|
? JSON.parse(message.payload.data)
|
||||||
|
: message.payload?.data || {};
|
||||||
|
return data?.type || "";
|
||||||
|
} catch (error) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 获取消息气泡样式类
|
// 获取消息气泡样式类
|
||||||
function getBubbleClass(message) {
|
function getBubbleClass(message) {
|
||||||
// 图片消息不需要气泡背景
|
// 图片消息不需要气泡背景
|
||||||
@ -397,7 +410,10 @@ function getBubbleClass(message) {
|
|||||||
return "image-bubble";
|
return "image-bubble";
|
||||||
}
|
}
|
||||||
if (message.type === "TIMCustomElem") {
|
if (message.type === "TIMCustomElem") {
|
||||||
return message.flow === "out" ? "" : "";
|
if (getCustomMessageType(message) === "benefit") {
|
||||||
|
return "benefit-bubble";
|
||||||
|
}
|
||||||
|
return "custom-bubble";
|
||||||
}
|
}
|
||||||
return message.flow === "out" ? "user-bubble" : "doctor-bubble";
|
return message.flow === "out" ? "user-bubble" : "doctor-bubble";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,11 +61,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import useAccount from "@/store/account";
|
||||||
import api from "@/utils/api";
|
import api from "@/utils/api";
|
||||||
import { normalizeCorpId } from "@/utils/api-base-config";
|
import { normalizeCorpId } from "@/utils/api-base-config";
|
||||||
import { toast } from "@/utils/widget";
|
import { useTeamAccess } from "@/hooks/use-team-access";
|
||||||
|
import { hideLoading, loading as showLoading, toast } from "@/utils/widget";
|
||||||
import FullPage from "@/components/full-page.vue";
|
import FullPage from "@/components/full-page.vue";
|
||||||
|
|
||||||
|
const env = __VITE_ENV__;
|
||||||
|
const appid = env.MP_WX_APP_ID;
|
||||||
|
const { account, externalUserId } = storeToRefs(useAccount());
|
||||||
|
const { getTeams, getExternalUserId, login } = useAccount();
|
||||||
|
const { openTeamLogin: openTeamInviteLogin, ensureTeamAdded: ensureJoinedTeam } = useTeamAccess();
|
||||||
|
|
||||||
const corpId = ref("");
|
const corpId = ref("");
|
||||||
const teamId = ref("");
|
const teamId = ref("");
|
||||||
const customerId = ref("");
|
const customerId = ref("");
|
||||||
@ -76,6 +85,10 @@ const records = ref([]);
|
|||||||
const staffNameMap = ref({});
|
const staffNameMap = ref({});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const refreshing = ref(false);
|
const refreshing = ref(false);
|
||||||
|
const corpUserId = ref("");
|
||||||
|
const routeExternalUserId = ref("");
|
||||||
|
const authPending = ref(false);
|
||||||
|
const initialized = ref(false);
|
||||||
|
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
pending: { label: "未到院" },
|
pending: { label: "未到院" },
|
||||||
@ -86,6 +99,126 @@ const statusMap = {
|
|||||||
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
|
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
|
||||||
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
|
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
|
||||||
|
|
||||||
|
function buildCurrentUrl() {
|
||||||
|
const params = [
|
||||||
|
`corpId=${encodeURIComponent(corpId.value || "")}`,
|
||||||
|
`teamId=${encodeURIComponent(teamId.value || "")}`,
|
||||||
|
customerId.value ? `customerId=${encodeURIComponent(customerId.value)}` : "",
|
||||||
|
customerName.value ? `name=${encodeURIComponent(customerName.value)}` : "",
|
||||||
|
corpName.value ? `corpName=${encodeURIComponent(corpName.value)}` : "",
|
||||||
|
corpUserId.value ? `corpUserId=${encodeURIComponent(corpUserId.value)}` : "",
|
||||||
|
routeExternalUserId.value ? `externalUserId=${encodeURIComponent(routeExternalUserId.value)}` : "",
|
||||||
|
selectedMonth.value ? `month=${encodeURIComponent(selectedMonth.value)}` : "",
|
||||||
|
].filter(Boolean).join("&");
|
||||||
|
return `/pages/record/appointment-record?${params}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureLogin() {
|
||||||
|
if (!account.value) await login();
|
||||||
|
if (!account.value) {
|
||||||
|
await ensureCustomerContext();
|
||||||
|
await openTeamLogin();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensurePhoneAuthorized() {
|
||||||
|
if (account.value?.mobile) return true;
|
||||||
|
await ensureCustomerContext();
|
||||||
|
return openTeamLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openTeamLogin() {
|
||||||
|
if (!corpId.value || !teamId.value) {
|
||||||
|
toast("预约团队信息缺失,暂无法查看预约记录");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const res = await openTeamInviteLogin({
|
||||||
|
corpId: corpId.value,
|
||||||
|
teamId: teamId.value,
|
||||||
|
corpUserId: corpUserId.value || "",
|
||||||
|
externalUserId: routeExternalUserId.value || externalUserId.value || "",
|
||||||
|
fallbackCorpName: corpName.value || "",
|
||||||
|
redirectUrl: buildCurrentUrl(),
|
||||||
|
});
|
||||||
|
if (!res.success) toast(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureCustomerContext() {
|
||||||
|
if (!corpId.value || !customerId.value) return null;
|
||||||
|
const res = await api("getCustomerByCustomerId", { corpId: corpId.value, customerId: customerId.value }, false);
|
||||||
|
const customer = res?.success && res.data ? res.data : null;
|
||||||
|
if (!customer) return null;
|
||||||
|
if (!customerName.value && customer.name) customerName.value = customer.name;
|
||||||
|
const teamIds = Array.isArray(customer.teamId) ? customer.teamId : [customer.teamId].filter(Boolean);
|
||||||
|
if (!teamId.value) teamId.value = teamIds.find(Boolean) || "";
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureTeamAdded() {
|
||||||
|
await ensureCustomerContext();
|
||||||
|
if (!corpId.value || !teamId.value) {
|
||||||
|
toast("预约团队信息缺失,暂无法查看预约记录");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
showLoading("添加团队中...");
|
||||||
|
try {
|
||||||
|
const res = await ensureJoinedTeam({
|
||||||
|
appid,
|
||||||
|
account: account.value,
|
||||||
|
getTeams,
|
||||||
|
corpId: corpId.value,
|
||||||
|
teamId: teamId.value,
|
||||||
|
});
|
||||||
|
if (!res.success) {
|
||||||
|
toast(res.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
hideLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureArchiveBound() {
|
||||||
|
const miniAppId = account.value?.openid || "";
|
||||||
|
if (!miniAppId || !corpId.value || !customerId.value) return false;
|
||||||
|
const customer = await ensureCustomerContext();
|
||||||
|
if (customer && String(customer.miniAppId || "") === String(miniAppId)) return true;
|
||||||
|
authPending.value = true;
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/archive/edit-archive?corpId=${encodeURIComponent(corpId.value)}&teamId=${encodeURIComponent(teamId.value)}&bindCustomerId=${encodeURIComponent(customerId.value)}&source=appointmentRegistration`,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ensureAccessReady() {
|
||||||
|
await ensureCustomerContext();
|
||||||
|
const okLogin = await ensureLogin();
|
||||||
|
if (!okLogin) return false;
|
||||||
|
const okPhone = await ensurePhoneAuthorized();
|
||||||
|
if (!okPhone) return false;
|
||||||
|
await ensureCustomerContext();
|
||||||
|
if (corpId.value) await getExternalUserId(corpId.value);
|
||||||
|
const okTeam = await ensureTeamAdded();
|
||||||
|
if (!okTeam) return false;
|
||||||
|
const okArchive = await ensureArchiveBound();
|
||||||
|
if (!okArchive) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadCorpName() {
|
||||||
|
if (!corpId.value) {
|
||||||
|
corpName.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await api("getCorpInfo", { corpId: corpId.value }, false);
|
||||||
|
const corp = Array.isArray(res?.data) ? res.data[0] : null;
|
||||||
|
corpName.value = corp?.corp_name || corp?.corpName || "";
|
||||||
|
}
|
||||||
|
|
||||||
function pad(value) {
|
function pad(value) {
|
||||||
return String(value).padStart(2, "0");
|
return String(value).padStart(2, "0");
|
||||||
}
|
}
|
||||||
@ -126,13 +259,13 @@ function statusText(item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function appointmentTypeText(item) {
|
function appointmentTypeText(item) {
|
||||||
if (item?.appointmentType === "schedule") return item?.scheduleTtile || "排班";
|
if (item?.appointmentType === "followup") return "复诊预约";
|
||||||
if (item?.appointmentType === "medical") return "复诊预约";
|
if (item?.appointmentType === "treatment") return "治疗预约";
|
||||||
return "治疗预约";
|
return "其他预约";
|
||||||
}
|
}
|
||||||
|
|
||||||
function practitionerLabel(item) {
|
function practitionerLabel(item) {
|
||||||
return item?.appointmentType === "medical" ? "医生" : "治疗师";
|
return item?.appointmentType === "treatment" ? "治疗师" : "医生";
|
||||||
}
|
}
|
||||||
|
|
||||||
function practitionerText(item) {
|
function practitionerText(item) {
|
||||||
@ -243,13 +376,28 @@ onLoad(async (options = {}) => {
|
|||||||
customerId.value = options.customerId || options.id || "";
|
customerId.value = options.customerId || options.id || "";
|
||||||
customerName.value = options.name ? decodeURIComponent(options.name) : "";
|
customerName.value = options.name ? decodeURIComponent(options.name) : "";
|
||||||
corpName.value = options.corpName ? decodeURIComponent(options.corpName) : "";
|
corpName.value = options.corpName ? decodeURIComponent(options.corpName) : "";
|
||||||
|
corpUserId.value = options.corpUserId || "";
|
||||||
|
routeExternalUserId.value = options.externalUserId || "";
|
||||||
if (options.month) selectedMonth.value = options.month;
|
if (options.month) selectedMonth.value = options.month;
|
||||||
|
await loadCorpName();
|
||||||
|
const ready = await ensureAccessReady();
|
||||||
|
if (!ready) return;
|
||||||
|
initialized.value = true;
|
||||||
await loadStaffNameMap();
|
await loadStaffNameMap();
|
||||||
await loadRecords();
|
await loadRecords();
|
||||||
});
|
});
|
||||||
|
|
||||||
onShow(() => {
|
onShow(async () => {
|
||||||
if (corpId.value && customerId.value) loadRecords();
|
if (authPending.value) {
|
||||||
|
authPending.value = false;
|
||||||
|
const ready = await ensureAccessReady();
|
||||||
|
if (!ready) return;
|
||||||
|
initialized.value = true;
|
||||||
|
await loadStaffNameMap();
|
||||||
|
await loadRecords();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (initialized.value && corpId.value && customerId.value) loadRecords();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -47,18 +47,6 @@
|
|||||||
<text class="row-value strong">{{ item.treatmentDoctorName || item.doctorName ||
|
<text class="row-value strong">{{ item.treatmentDoctorName || item.doctorName ||
|
||||||
staffText(item.treatmentDoctorUserId) }}</text>
|
staffText(item.treatmentDoctorUserId) }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view v-if="assistantText(item)" class="record-row">
|
|
||||||
<text class="row-label">【配台】</text>
|
|
||||||
<text class="row-value">{{ assistantText(item) }}</text>
|
|
||||||
</view>
|
|
||||||
<view v-if="item.treatmentArea" class="record-row">
|
|
||||||
<text class="row-label">【治疗部位】</text>
|
|
||||||
<text class="row-value">{{ item.treatmentArea }}</text>
|
|
||||||
</view>
|
|
||||||
<view v-if="item.treatmentRemark" class="record-row">
|
|
||||||
<text class="row-label">【治疗备注】</text>
|
|
||||||
<text class="row-value">{{ item.treatmentRemark }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@ -88,6 +76,16 @@ const refreshing = ref(false);
|
|||||||
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
|
const avatarText = computed(() => (customerName.value || "档案").slice(0, 1));
|
||||||
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
|
const monthText = computed(() => selectedMonth.value.replace("-", "年") + "月");
|
||||||
|
|
||||||
|
async function loadCorpName() {
|
||||||
|
if (!corpId.value) {
|
||||||
|
corpName.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await api("getCorpInfo", { corpId: corpId.value }, false);
|
||||||
|
const corp = Array.isArray(res?.data) ? res.data[0] : null;
|
||||||
|
corpName.value = corp?.corp_name || corp?.corpName || "";
|
||||||
|
}
|
||||||
|
|
||||||
function pad(value) {
|
function pad(value) {
|
||||||
return String(value).padStart(2, "0");
|
return String(value).padStart(2, "0");
|
||||||
}
|
}
|
||||||
@ -211,8 +209,8 @@ onLoad(async (options = {}) => {
|
|||||||
teamId.value = options.teamId || "";
|
teamId.value = options.teamId || "";
|
||||||
customerId.value = options.customerId || options.id || "";
|
customerId.value = options.customerId || options.id || "";
|
||||||
customerName.value = options.name ? decodeURIComponent(options.name) : "";
|
customerName.value = options.name ? decodeURIComponent(options.name) : "";
|
||||||
corpName.value = options.corpName ? decodeURIComponent(options.corpName) : "";
|
|
||||||
if (options.month) selectedMonth.value = options.month;
|
if (options.month) selectedMonth.value = options.month;
|
||||||
|
await loadCorpName();
|
||||||
await loadStaffNameMap();
|
await loadStaffNameMap();
|
||||||
await loadRecords();
|
await loadRecords();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -159,11 +159,12 @@ export default defineStore("accountStore", () => {
|
|||||||
const normalizedCorpId = normalizeCorpId(corpId);
|
const normalizedCorpId = normalizeCorpId(corpId);
|
||||||
const unionid = account.value?.unionid;
|
const unionid = account.value?.unionid;
|
||||||
const openid = account.value?.openid;
|
const openid = account.value?.openid;
|
||||||
|
const miniAppId = account.value?.openid;
|
||||||
if (!(normalizedCorpId && unionid && openid)) {
|
if (!(normalizedCorpId && unionid && openid)) {
|
||||||
externalUserId.value = '';
|
externalUserId.value = '';
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
const res = await api('getUnionidToExternalUserid', { unionid, openid, corpId: normalizedCorpId }, false);
|
const res = await api('getUnionidToExternalUserid', { unionid, openid, corpId: normalizedCorpId, miniAppId }, false);
|
||||||
const id = res && res.success && typeof res.data === 'string' && res.data.trim() ? res.data.trim() : '';
|
const id = res && res.success && typeof res.data === 'string' && res.data.trim() ? res.data.trim() : '';
|
||||||
externalUserId.value = id;
|
externalUserId.value = id;
|
||||||
return id;
|
return id;
|
||||||
|
|||||||
@ -21,6 +21,7 @@ const urlsConfig = {
|
|||||||
recordBusinessCardBehavior: 'recordBusinessCardBehavior',
|
recordBusinessCardBehavior: 'recordBusinessCardBehavior',
|
||||||
getJoinedTeams: 'getJoinedTeams',
|
getJoinedTeams: 'getJoinedTeams',
|
||||||
getCorpBusinessCardStatus: 'getCorpBusinessCardStatus',
|
getCorpBusinessCardStatus: 'getCorpBusinessCardStatus',
|
||||||
|
getCorpInfo: 'getCorpInfo',
|
||||||
},
|
},
|
||||||
|
|
||||||
knowledgeBase: {
|
knowledgeBase: {
|
||||||
@ -62,6 +63,7 @@ const urlsConfig = {
|
|||||||
getExperienceCouponIssueDetail: "getExperienceCouponIssueDetail",
|
getExperienceCouponIssueDetail: "getExperienceCouponIssueDetail",
|
||||||
getExperienceCouponIssueList: "getExperienceCouponIssueList",
|
getExperienceCouponIssueList: "getExperienceCouponIssueList",
|
||||||
getMiniAppCustomers: 'getMiniAppCustomers',
|
getMiniAppCustomers: 'getMiniAppCustomers',
|
||||||
|
getCorpMiniAppCustomers: 'getCorpMiniAppCustomers',
|
||||||
getTeamCustomers: 'getTeamCustomers',
|
getTeamCustomers: 'getTeamCustomers',
|
||||||
getTreatmentRecord: "getTreatmentRecord",
|
getTreatmentRecord: "getTreatmentRecord",
|
||||||
getDeductRecord: "getDeductRecord",
|
getDeductRecord: "getDeductRecord",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user