ykt-wxapp/pages/case/batch-transfer.vue

293 lines
7.6 KiB
Vue
Raw Permalink Normal View History

2026-01-20 16:24:43 +08:00
<template>
<view class="transfer-container">
<view class="content">
<view class="section-title">选择新负责团队</view>
<view class="selector-item" @click="selectTeam">
<text :class="team ? '' : 'placeholder'">{{ team ? team.name : '请选择团队' }}</text>
<uni-icons type="arrowdown" size="16" color="#999" />
2026-01-20 16:24:43 +08:00
</view>
<template v-if="team">
<view class="section-title">选择责任人</view>
<view class="selector-item" @click="selectUser">
<text :class="userId ? '' : 'placeholder'">{{ userLabel || '请选择责任人' }}</text>
<uni-icons type="arrowdown" size="16" color="#999" />
2026-01-20 16:24:43 +08:00
</view>
</template>
<view class="tips">客户将与本团队解除服务关系本团队成员将没有权限查询到客户档案</view>
</view>
<view class="footer">
<button class="btn plain" @click="cancel">取消</button>
<button class="btn primary" @click="save">保存</button>
</view>
</view>
</template>
<script setup>
import { computed, ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { storeToRefs } from 'pinia';
import api from '@/utils/api';
import useAccountStore from '@/store/account';
import { hideLoading, loading, toast } from '@/utils/widget';
2026-01-20 16:24:43 +08:00
const CURRENT_TEAM_STORAGE_KEY = 'ykt_case_current_team';
const NEED_RELOAD_STORAGE_KEY = 'ykt_case_need_reload';
const BATCH_CUSTOMER_IDS_KEY = 'ykt_case_batch_customer_ids';
const accountStore = useAccountStore();
const { account, doctorInfo } = storeToRefs(accountStore);
const { getDoctorInfo } = accountStore;
const customerIds = ref([]);
const currentTeam = ref(null);
const teams = ref([]);
2026-01-20 16:24:43 +08:00
const team = ref(null);
const teamMembers = ref([]);
const userId = ref('');
const userLabel = computed(() => {
const list = Array.isArray(teamMembers.value) ? teamMembers.value : [];
const found = list.find((m) => String(m?.userid || '') === String(userId.value));
return found ? String(found.anotherName || found.name || found.userid || '') : '';
});
function getUserId() {
const d = doctorInfo.value || {};
const a = account.value || {};
return String(d.userid || d.userId || d.corpUserId || a.userid || a.userId || '') || '';
}
function getCorpId() {
const t = currentTeam.value || {};
const a = account.value || {};
const d = doctorInfo.value || {};
return String(t.corpId || d.corpId || a.corpId || '') || '';
}
function getCurrentTeamId() {
return String(currentTeam.value?.teamId || '') || '';
}
function normalizeTeam(raw) {
if (!raw || typeof raw !== 'object') return null;
const teamId = raw.teamId || raw.id || raw._id || '';
const name = raw.name || raw.teamName || raw.team || '';
const corpId = raw.corpId || raw.corpID || '';
if (!teamId || !name) return null;
return { teamId: String(teamId), name: String(name), corpId: corpId ? String(corpId) : '' };
}
async function ensureDoctor() {
if (doctorInfo.value) return;
if (!account.value?.openid) return;
try {
await getDoctorInfo();
} catch (e) {
// ignore
}
}
async function loadTeams() {
await ensureDoctor();
const corpId = getCorpId();
const userId = getUserId();
if (!corpId || !userId) return;
const res = await api('getTeamBymember', { corpId, corpUserId: userId });
if (!res?.success) {
toast(res?.message || '获取团队失败');
return;
}
const list = Array.isArray(res?.data) ? res.data : Array.isArray(res?.data?.data) ? res.data.data : [];
teams.value = list.map(normalizeTeam).filter(Boolean);
}
async function loadTeamMembers(teamId) {
const corpId = getCorpId();
if (!teamId) return;
const res = await api('getTeamData', { corpId, teamId });
if (!res?.success) {
toast(res?.message || '获取团队成员失败');
teamMembers.value = [];
return;
}
const t = res?.data && typeof res.data === 'object' ? res.data : {};
teamMembers.value = Array.isArray(t.memberList) ? t.memberList : [];
}
const selectTeam = async () => {
if (!teams.value.length) await loadTeams();
const currentId = getCurrentTeamId();
const candidates = teams.value.filter((t) => t.teamId !== currentId);
if (!candidates.length) {
toast('暂无可选团队');
return;
}
2026-01-20 16:24:43 +08:00
uni.showActionSheet({
itemList: candidates.map((t) => t.name),
success: async (res) => {
team.value = candidates[res.tapIndex] || null;
userId.value = '';
teamMembers.value = [];
if (team.value) await loadTeamMembers(team.value.teamId);
},
2026-01-20 16:24:43 +08:00
});
};
const selectUser = () => {
const list = Array.isArray(teamMembers.value) ? teamMembers.value : [];
if (!list.length) {
toast('当前团队暂无可选成员');
return;
}
const labels = list.map((m) => String(m?.anotherName || m?.name || m?.userid || ''));
2026-01-20 16:24:43 +08:00
uni.showActionSheet({
itemList: labels,
2026-01-20 16:24:43 +08:00
success: (res) => {
const picked = list[res.tapIndex];
userId.value = picked?.userid ? String(picked.userid) : '';
},
2026-01-20 16:24:43 +08:00
});
};
const cancel = () => {
uni.navigateBack();
};
const save = async () => {
if (!team.value) return toast('请选择团队');
if (!userId.value) return toast('请选择负责人');
const corpId = getCorpId();
const currentTeamId = getCurrentTeamId();
const creatorUserId = getUserId();
if (!corpId || !currentTeamId || !creatorUserId) return toast('缺少用户/团队信息');
loading('保存中...');
try {
const res = await api('transferCustomers', {
corpId,
customerIds: customerIds.value,
currentTeamId,
targetTeamId: team.value.teamId,
targetUserId: userId.value,
operationType: 'transferToOtherTeam',
creatorUserId,
});
if (!res?.success) {
toast(res?.message || '操作失败');
return;
}
toast('操作成功');
uni.removeStorageSync(BATCH_CUSTOMER_IDS_KEY);
uni.setStorageSync(NEED_RELOAD_STORAGE_KEY, 1);
uni.navigateBack();
} catch (e) {
toast('操作失败');
} finally {
hideLoading();
2026-01-20 16:24:43 +08:00
}
};
onLoad(async () => {
customerIds.value = Array.isArray(uni.getStorageSync(BATCH_CUSTOMER_IDS_KEY))
? uni.getStorageSync(BATCH_CUSTOMER_IDS_KEY).map(String).filter(Boolean)
: [];
currentTeam.value = uni.getStorageSync(CURRENT_TEAM_STORAGE_KEY) || null;
if (!customerIds.value.length) {
toast('未选择客户');
setTimeout(() => uni.navigateBack(), 200);
2026-01-20 16:24:43 +08:00
return;
}
await loadTeams();
});
2026-01-20 16:24:43 +08:00
</script>
<style lang="scss" scoped>
.transfer-container {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f7f8fa;
}
.content {
flex: 1;
padding: 20px;
.section-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-top: 20px;
margin-bottom: 10px;
2026-01-20 16:24:43 +08:00
&:first-child {
margin-top: 0;
}
}
.selector-item {
background-color: #fff;
height: 44px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 15px;
2026-01-20 16:24:43 +08:00
text {
font-size: 14px;
color: #333;
2026-01-20 16:24:43 +08:00
&.placeholder {
color: #999;
}
}
}
.tips {
margin-top: 15px;
font-size: 14px;
color: #999;
line-height: 1.5;
}
}
.footer {
background-color: #fff;
padding: 15px 20px 30px;
display: flex;
gap: 15px;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
2026-01-20 16:24:43 +08:00
.btn {
flex: 1;
height: 44px;
line-height: 44px;
font-size: 16px;
border-radius: 4px;
margin: 0;
&.plain {
background-color: #fff;
color: #666;
border: 1px solid #ddd;
}
&.primary {
background-color: #5d8aff;
color: #fff;
border: none;
}
2026-01-20 16:24:43 +08:00
&::after {
border: none;
}
}
}
</style>