bug修复
This commit is contained in:
parent
1e0cd71432
commit
c33f9929d1
@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<page-meta :page-style="projectPickerVisible || todoExecutorPickerVisible ? 'overflow: hidden;' : ''"></page-meta>
|
||||
<full-page ref="pageRef" pageStyle="background:#f5f6f8" pageClass="benefit-page-shell">
|
||||
<view class="benefit-page">
|
||||
<view class="patient-card">
|
||||
@ -42,7 +43,9 @@
|
||||
</view>
|
||||
<view class="field-block">
|
||||
<view class="field-label">折扣</view>
|
||||
<input class="number-input" type="digit" v-model="entry.discount" @input="calculatePackageTotal(entry)" />
|
||||
<picker class="discount-picker" mode="multiSelector" :range="getDiscountPickerRange(entry)" :value="getDiscountPickerValue(entry)" :disabled="!entry.enableDiscount" @change="changeDiscount($event, entry)">
|
||||
<view class="number-input picker-value value-text">{{ Number(entry.discount).toFixed(1) }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view class="field-block">
|
||||
<view class="field-label">总价</view>
|
||||
@ -120,8 +123,10 @@
|
||||
<view class="field-block">
|
||||
<view class="field-label">折扣</view>
|
||||
<view class="discount-input-wrap">
|
||||
<input class="number-input" type="digit" v-model="entry.discount" :disabled="entry.isFree" @input="calculateTotalPrice(entry)" />
|
||||
<checkbox-group class="free-check" @change="handleFreeChange($event, entry)">
|
||||
<picker class="discount-picker" mode="multiSelector" :range="getDiscountPickerRange(entry)" :value="getDiscountPickerValue(entry)" :disabled="entry.isFree || !entry.isDiscount" @change="changeDiscount($event, entry)">
|
||||
<view class="number-input picker-value value-text">{{ Number(entry.discount).toFixed(1) }}</view>
|
||||
</picker>
|
||||
<checkbox-group v-if="entry.isGift" class="free-check" @change="handleFreeChange($event, entry)">
|
||||
<label class="free-check-label">
|
||||
<checkbox value="free" :checked="entry.isFree" color="#0877f1" />
|
||||
<text>赠送</text>
|
||||
@ -131,7 +136,7 @@
|
||||
</view>
|
||||
<view class="field-block">
|
||||
<view class="field-label">总价</view>
|
||||
<input class="number-input total-input" type="digit" v-model="entry.totalPrice" :disabled="entry.isFree" @input="calculateDiscount(entry)" />
|
||||
<input class="number-input total-input" type="digit" v-model="entry.totalPrice" :disabled="entry.isFree || !entry.isDiscount" @input="calculateDiscount(entry)" />
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="field-row">
|
||||
@ -196,18 +201,6 @@
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view v-if="entry.project?._id" class="todo-switch-row">
|
||||
<text>生成待办</text>
|
||||
<switch :checked="entry.todoEnabled" color="#0877f1" @change="toggleTodo($event, entry)" />
|
||||
</view>
|
||||
<view v-if="entry.project?._id && entry.todoEnabled" class="todo-config-card">
|
||||
<input v-model="entry.todoConfig.taskContent" class="todo-input" placeholder="任务内容" />
|
||||
<picker :range="todoTypeOptions" range-key="label" @change="changeTodoType($event, entry)"><view class="project-input"><text>类型:{{ getTodoTypeLabel(entry.todoConfig.eventType) }}</text><uni-icons type="right" size="16" color="#999" /></view></picker>
|
||||
<view class="field-row"><view class="field-block"><view class="field-label">回访日期</view><view class="valid-time-picker" @tap="prepareTodoDatePicker(entry, 'planDate')"><picker mode="multiSelector" :range="validTimeRange" :value="validTimeIndex" @columnchange="onValidTimeColumnChange" @change="changeTodoDate($event)"><view class="picker-value value-text">{{ entry.todoConfig.planDate }}</view></picker></view></view><view class="field-block"><view class="field-label">截止日期</view><view class="valid-time-picker" @tap="prepareTodoDatePicker(entry, 'expireDate')"><picker mode="multiSelector" :range="validTimeRange" :value="validTimeIndex" @columnchange="onValidTimeColumnChange" @change="changeTodoDate($event)"><view class="picker-value value-text">{{ entry.todoConfig.expireDate }}</view></picker></view></view></view>
|
||||
<view class="project-input" @tap="openTodoExecutorPicker(entry)"><text :class="entry.todoConfig.executorUserId ? 'value-text' : 'placeholder-text'">{{ entry.todoConfig.executorName || '请选择团队和处理人' }}</text><uni-icons type="right" size="16" color="#999" /></view>
|
||||
<view class="todo-deduct-row"><text>完成关联核销权益</text><switch :checked="entry.todoConfig.deductBenefit" color="#0877f1" @change="entry.todoConfig.deductBenefit = $event.detail.value" /></view>
|
||||
</view>
|
||||
|
||||
<view class="field-group">
|
||||
<view class="field-label">计划治疗医生</view>
|
||||
<picker
|
||||
@ -224,6 +217,18 @@
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
<view v-if="entry.project?._id" class="todo-switch-row">
|
||||
<text>生成待办</text>
|
||||
<switch :checked="entry.todoEnabled" color="#0877f1" @change="toggleTodo($event, entry)" />
|
||||
</view>
|
||||
<view v-if="entry.project?._id && entry.todoEnabled" class="todo-config-card">
|
||||
<input v-model="entry.todoConfig.taskContent" class="todo-input" placeholder="任务内容" />
|
||||
<picker :range="todoTypeOptions" range-key="label" @change="changeTodoType($event, entry)"><view class="project-input"><text>类型:{{ getTodoTypeLabel(entry.todoConfig.eventType) }}</text><uni-icons type="right" size="16" color="#999" /></view></picker>
|
||||
<view class="field-row"><view class="field-block"><view class="field-label">回访日期</view><view class="valid-time-picker" @tap="prepareTodoDatePicker(entry, 'planDate')"><picker mode="multiSelector" :range="validTimeRange" :value="validTimeIndex" @columnchange="onValidTimeColumnChange" @change="changeTodoDate($event)"><view class="picker-value value-text">{{ entry.todoConfig.planDate }}</view></picker></view></view><view class="field-block"><view class="field-label">截止日期</view><view class="valid-time-picker" @tap="prepareTodoDatePicker(entry, 'expireDate')"><picker mode="multiSelector" :range="validTimeRange" :value="validTimeIndex" @columnchange="onValidTimeColumnChange" @change="changeTodoDate($event)"><view class="picker-value value-text">{{ entry.todoConfig.expireDate }}</view></picker></view></view></view>
|
||||
<view class="project-input" @tap="openTodoExecutorPicker(entry)"><text :class="entry.todoConfig.executorUserId ? 'value-text' : 'placeholder-text'">{{ entry.todoConfig.executorName || '请选择团队和处理人' }}</text><uni-icons type="right" size="16" color="#999" /></view>
|
||||
<view class="todo-deduct-row"><text>完成关联核销权益</text><switch :checked="entry.todoConfig.deductBenefit" color="#0877f1" @change="entry.todoConfig.deductBenefit = $event.detail.value" /></view>
|
||||
</view>
|
||||
|
||||
<view v-if="entries.length > 1" class="remove-entry" @click="removeEntry(index)">删除此项目</view>
|
||||
</template>
|
||||
</view>
|
||||
@ -234,30 +239,40 @@
|
||||
</view>
|
||||
|
||||
<view v-if="todoExecutorPickerVisible" class="picker-mask" @click="closeTodoExecutorPicker">
|
||||
<view class="todo-executor-picker" @click.stop>
|
||||
<view class="todo-executor-picker" :style="{ '--keyboard-height': `${keyboardHeight}px` }" @click.stop>
|
||||
<view class="picker-header"><text class="picker-title">请选择团队和处理人</text><uni-icons type="closeempty" size="22" color="#666" @click="closeTodoExecutorPicker" /></view>
|
||||
<scroll-view scroll-y class="todo-executor-list">
|
||||
<view v-for="team in todoTeams" :key="team.teamId" class="todo-team-group">
|
||||
<view class="todo-executor-search">
|
||||
<uni-icons type="search" size="18" color="#999" />
|
||||
<input v-model="todoExecutorKeyword" class="todo-executor-search-input" :adjust-position="false" placeholder="搜索团队或处理人" />
|
||||
</view>
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="todo-executor-list"
|
||||
:refresher-enabled="true"
|
||||
:refresher-triggered="todoExecutorRefreshing"
|
||||
@refresherrefresh="refreshTodoExecutors"
|
||||
>
|
||||
<view v-for="team in filteredTodoTeams" :key="team.teamId" class="todo-team-group">
|
||||
<view class="todo-team-title">{{ team.name }}</view>
|
||||
<view v-for="member in getTodoExecutorsForTeam(team)" :key="member.userid" class="todo-executor-item" @tap="selectTodoExecutor(member, team)">
|
||||
<text>{{ member.name }}</text><text v-if="isSelectedTodoExecutor(member, team)" class="todo-selected">已选择</text>
|
||||
</view>
|
||||
<view v-if="!getTodoExecutorsForTeam(team).length" class="todo-empty">暂无团队成员</view>
|
||||
</view>
|
||||
<view v-if="!todoTeams.length" class="todo-empty">暂无可选团队</view>
|
||||
<view v-if="!filteredTodoTeams.length" class="todo-empty">暂无匹配的团队或处理人</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="projectPickerVisible" class="picker-mask" @click="closeProjectPicker">
|
||||
<view class="project-picker" @click.stop>
|
||||
<view class="project-picker" :style="{ '--keyboard-height': `${keyboardHeight}px` }" @click.stop>
|
||||
<view class="picker-header">
|
||||
<text class="picker-title">选择权益项目或套餐</text>
|
||||
<uni-icons type="closeempty" size="22" color="#666" @click="closeProjectPicker" />
|
||||
</view>
|
||||
<view class="search-box">
|
||||
<uni-icons type="search" size="18" color="#999" />
|
||||
<input v-model="projectKeyword" class="search-input" placeholder="输入项目或套餐名称搜索" @input="searchProjects" />
|
||||
<input v-model="projectKeyword" class="search-input" :adjust-position="false" placeholder="输入项目或套餐名称搜索" @input="searchProjects" />
|
||||
</view>
|
||||
<scroll-view scroll-y class="project-list" @scrolltolower="loadMoreProjects">
|
||||
<view v-if="projectList.length" class="picker-group-title">单项目</view>
|
||||
@ -292,7 +307,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, ref } from "vue";
|
||||
import { computed, nextTick, onUnmounted, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import api from "@/utils/api.js";
|
||||
import useAccountStore from "@/store/account.js";
|
||||
@ -315,6 +330,7 @@ const entries = ref([]);
|
||||
const saving = ref(false);
|
||||
const projectPickerVisible = ref(false);
|
||||
const projectPickerIndex = ref(-1);
|
||||
const keyboardHeight = ref(0);
|
||||
const projectKeyword = ref("");
|
||||
const projectList = ref([]);
|
||||
const packageList = ref([]);
|
||||
@ -331,6 +347,8 @@ const teamMembers = ref([]);
|
||||
const todoTeams = ref([]);
|
||||
const todoExecutorPickerVisible = ref(false);
|
||||
const todoExecutorTarget = ref(null);
|
||||
const todoExecutorKeyword = ref("");
|
||||
const todoExecutorRefreshing = ref(false);
|
||||
const todoTypeOptions = Object.entries(TODO_EVENT_TYPE_LABELS).map(([value, label]) => ({ value, label }));
|
||||
let searchTimer = null;
|
||||
let entryKey = 0;
|
||||
@ -437,6 +455,11 @@ function createEntry() {
|
||||
totalPrice: 0,
|
||||
discount: 10,
|
||||
isFree: false,
|
||||
isGift: false,
|
||||
isDiscount: false,
|
||||
lowestDiscount: 10,
|
||||
enableDiscount: false,
|
||||
minDiscount: 10,
|
||||
usageCount: 1,
|
||||
validTime: "",
|
||||
dept: null,
|
||||
@ -456,6 +479,10 @@ function decodeRouteParam(value = "") {
|
||||
}
|
||||
|
||||
onLoad((options = {}) => {
|
||||
uni.onKeyboardHeightChange((res) => {
|
||||
keyboardHeight.value = Number(res?.height || 0);
|
||||
});
|
||||
|
||||
groupId.value = decodeRouteParam(options.groupId);
|
||||
patientId.value = decodeRouteParam(options.patientId);
|
||||
patientName.value = decodeRouteParam(options.patientName);
|
||||
@ -470,6 +497,10 @@ onLoad((options = {}) => {
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
uni.offKeyboardHeightChange();
|
||||
});
|
||||
|
||||
async function loadTeamContext() {
|
||||
if (!teamId.value || !corpId.value) return;
|
||||
try {
|
||||
@ -508,22 +539,33 @@ async function loadStaffList() {
|
||||
}
|
||||
|
||||
async function loadTodoTeams() {
|
||||
const userId = accountStore.doctorInfo?.userid || accountStore.account?.userid || "";
|
||||
if (!corpId.value || !userId) return;
|
||||
if (!corpId.value) return;
|
||||
try {
|
||||
const res = await api("getTeamBymember", { corpId: corpId.value, corpUserId: userId }, false);
|
||||
const list = Array.isArray(res?.data) ? res.data : Array.isArray(res?.data?.data) ? res.data.data : [];
|
||||
const res = await api("getAllTeamByCorp", { corpId: corpId.value }, false);
|
||||
const list = Array.isArray(res?.data)
|
||||
? res.data
|
||||
: Array.isArray(res?.data?.data)
|
||||
? res.data.data
|
||||
: Array.isArray(res?.data?.list)
|
||||
? res.data.list
|
||||
: Array.isArray(res?.list)
|
||||
? res.list
|
||||
: [];
|
||||
const baseTeams = list.length ? list : [{ teamId: teamId.value, name: teamName.value, memberList: teamMembers.value }];
|
||||
const details = await Promise.all(baseTeams.map(async (team) => {
|
||||
const currentTeamId = team.teamId || team._id || team.id;
|
||||
if (!currentTeamId) return null;
|
||||
if (Array.isArray(team.memberList)) {
|
||||
return { teamId: currentTeamId, name: team.name || team.teamName || "未命名团队", memberList: team.memberList };
|
||||
}
|
||||
const detailRes = await api("getTeamData", { corpId: corpId.value, teamId: currentTeamId }, false);
|
||||
const detail = detailRes?.data || {};
|
||||
return { teamId: currentTeamId, name: detail.name || team.name || team.teamName || "未命名团队", memberList: detail.memberList || team.memberList || [] };
|
||||
return { teamId: currentTeamId, name: detail.name || team.name || team.teamName || "未命名团队", memberList: detail.memberList || [] };
|
||||
}));
|
||||
todoTeams.value = details.filter(Boolean);
|
||||
} catch (error) {
|
||||
todoTeams.value = teamId.value ? [{ teamId: teamId.value, name: teamName.value, memberList: teamMembers.value }] : [];
|
||||
console.error("加载机构团队失败", error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,10 +679,23 @@ function calculateTotalPrice(entry) {
|
||||
entry.totalPrice = 0;
|
||||
return;
|
||||
}
|
||||
entry.discount = normalizeDiscount(entry);
|
||||
const total = toNumber(entry.price) * toNumber(entry.usageCount, 1) * (toNumber(entry.discount) / 10);
|
||||
entry.totalPrice = toFixedNumber(Math.max(0, total), 2);
|
||||
}
|
||||
|
||||
function changeDiscount(event, entry) {
|
||||
const pickerRange = getDiscountPickerRange(entry);
|
||||
const integer = pickerRange[0][Number(event.detail.value[0])] || "10";
|
||||
const decimal = pickerRange[1][Number(event.detail.value[1])] || "0";
|
||||
entry.discount = normalizeDiscount({ ...entry, discount: `${integer}.${decimal}` });
|
||||
if (entry.isPackage) {
|
||||
calculatePackageTotal(entry);
|
||||
} else {
|
||||
calculateTotalPrice(entry);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateDiscount(entry) {
|
||||
if (entry.isFree) {
|
||||
entry.discount = 0;
|
||||
@ -649,21 +704,56 @@ function calculateDiscount(entry) {
|
||||
}
|
||||
const originalTotal = toNumber(entry.price) * toNumber(entry.usageCount);
|
||||
entry.discount = originalTotal > 0
|
||||
? toFixedNumber(clampNumber((toNumber(entry.totalPrice) / originalTotal) * 10, 0, 10), 1)
|
||||
: 10;
|
||||
? normalizeDiscount({ ...entry, discount: toFixedNumber((toNumber(entry.totalPrice) / originalTotal) * 10, 1) })
|
||||
: normalizeDiscount(entry);
|
||||
}
|
||||
|
||||
function handleFreeChange(event, entry) {
|
||||
if (!entry.isGift) {
|
||||
entry.isFree = false;
|
||||
return;
|
||||
}
|
||||
entry.isFree = Array.isArray(event.detail.value) && event.detail.value.includes("free");
|
||||
if (entry.isFree) {
|
||||
entry.discount = 0;
|
||||
entry.totalPrice = 0;
|
||||
return;
|
||||
}
|
||||
entry.discount = 10;
|
||||
entry.discount = normalizeDiscount({ ...entry, discount: 10 });
|
||||
calculateTotalPrice(entry);
|
||||
}
|
||||
|
||||
function getDiscountMin(entry) {
|
||||
const minDiscount = entry.isPackage ? entry.minDiscount : entry.lowestDiscount;
|
||||
return Number(minDiscount) > 0 ? Number(minDiscount) : 0;
|
||||
}
|
||||
|
||||
function getDiscountPickerRange(entry) {
|
||||
const supportsDiscount = entry.isPackage ? entry.enableDiscount : entry.isDiscount;
|
||||
if (!supportsDiscount) return [["10"], ["0"]];
|
||||
const min = Math.min(10, Math.max(0, toNumber(getDiscountMin(entry))));
|
||||
const integers = [];
|
||||
for (let value = Math.floor(min); value <= 10; value += 1) {
|
||||
integers.push(String(value));
|
||||
}
|
||||
return [integers, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]];
|
||||
}
|
||||
|
||||
function getDiscountPickerValue(entry) {
|
||||
const discount = normalizeDiscount(entry).toFixed(1).split(".");
|
||||
const range = getDiscountPickerRange(entry);
|
||||
const integerIndex = Math.max(0, range[0].indexOf(discount[0]));
|
||||
const decimalIndex = Math.max(0, range[1].indexOf(discount[1] || "0"));
|
||||
return [integerIndex, decimalIndex];
|
||||
}
|
||||
|
||||
function normalizeDiscount(entry) {
|
||||
const discount = toNumber(entry.discount, 0);
|
||||
const supportsDiscount = entry.isPackage ? entry.enableDiscount : entry.isDiscount;
|
||||
if (!supportsDiscount) return 10;
|
||||
return toFixedNumber(clampNumber(discount, getDiscountMin(entry), 10), 1);
|
||||
}
|
||||
|
||||
function getProjectDepts(entry) {
|
||||
return Array.isArray(entry?.project?.depts) ? entry.project.depts : [];
|
||||
}
|
||||
@ -686,7 +776,10 @@ function selectProject(project) {
|
||||
const normalizedProject = normalizeProject(project);
|
||||
entry.project = normalizedProject;
|
||||
entry.price = Number(normalizedProject.price || 0);
|
||||
entry.discount = 10;
|
||||
entry.isGift = normalizedProject.isGift === true;
|
||||
entry.isDiscount = normalizedProject.isDiscount === true;
|
||||
entry.lowestDiscount = Number(normalizedProject.lowestDiscount || 0);
|
||||
entry.discount = normalizeDiscount({ ...entry, discount: 10 });
|
||||
entry.isFree = false;
|
||||
calculateTotalPrice(entry);
|
||||
entry.dept = getProjectDepts(entry).length === 1 ? getProjectDepts(entry)[0] : null;
|
||||
@ -709,6 +802,8 @@ function createPackageProjectEntry(project = {}, packageItem = {}) {
|
||||
usageCount: Number(project.number || 1),
|
||||
packageUnitUsageCount: Number(project.number || 1),
|
||||
discount: packageItem.packageType === "free" ? 10 : Number(project.discount || 10),
|
||||
enableDiscount: packageItem.enableDiscount === true,
|
||||
minDiscount: Number(packageItem.minDiscount || 0),
|
||||
totalPrice: Number(project.totalPrice || 0),
|
||||
selected: packageItem.packageType === "fixed" || project.required === true,
|
||||
required: project.required === true,
|
||||
@ -742,6 +837,8 @@ async function selectPackage(packageItem) {
|
||||
price: Number(packageItem.packagePrice || 0),
|
||||
usageCount: 1,
|
||||
discount: 10,
|
||||
enableDiscount: packageItem.enableDiscount === true,
|
||||
minDiscount: Number(packageItem.minDiscount || 0),
|
||||
totalPrice: Number(packageItem.packagePrice || 0),
|
||||
projectNumber: Number(packageItem.projectNumber || projects.length),
|
||||
requiredCount,
|
||||
@ -782,7 +879,7 @@ function togglePackageProject(entry, projectEntry) {
|
||||
|
||||
function calculatePackageTotal(entry) {
|
||||
entry.usageCount = Math.max(1, Number(entry.usageCount || 1));
|
||||
entry.discount = clampNumber(toNumber(entry.discount, 10), 0, 10);
|
||||
entry.discount = normalizeDiscount(entry);
|
||||
entry.totalPrice = toFixedNumber(Number(entry.price || 0) * entry.usageCount * entry.discount / 10, 2);
|
||||
entry.projects.filter((project) => project.selected).forEach((project) => {
|
||||
project.usageCount = entry.usageCount * Number(project.packageUnitUsageCount || 1);
|
||||
@ -829,12 +926,15 @@ function getTodoExecutors(entry) {
|
||||
|
||||
function openTodoExecutorPicker(entry) {
|
||||
todoExecutorTarget.value = entry;
|
||||
todoExecutorKeyword.value = "";
|
||||
todoExecutorPickerVisible.value = true;
|
||||
if (!todoTeams.value.length) refreshTodoExecutors();
|
||||
}
|
||||
|
||||
function closeTodoExecutorPicker() {
|
||||
todoExecutorPickerVisible.value = false;
|
||||
todoExecutorTarget.value = null;
|
||||
todoExecutorKeyword.value = "";
|
||||
}
|
||||
|
||||
function getTodoExecutorsForTeam(team) {
|
||||
@ -845,6 +945,29 @@ function getTodoExecutorsForTeam(team) {
|
||||
}).filter((member) => member.userid);
|
||||
}
|
||||
|
||||
const filteredTodoTeams = computed(() => {
|
||||
const keyword = todoExecutorKeyword.value.trim().toLowerCase();
|
||||
if (!keyword) return todoTeams.value;
|
||||
return todoTeams.value.map((team) => {
|
||||
const members = getTodoExecutorsForTeam(team).filter((member) => (
|
||||
String(member.name || "").toLowerCase().includes(keyword)
|
||||
|| String(member.userid || "").toLowerCase().includes(keyword)
|
||||
));
|
||||
const teamMatched = String(team.name || "").toLowerCase().includes(keyword);
|
||||
return { team: teamMatched ? team : { ...team, memberList: members }, matched: teamMatched || members.length > 0 };
|
||||
}).filter((item) => item.matched).map((item) => item.team);
|
||||
});
|
||||
|
||||
async function refreshTodoExecutors() {
|
||||
if (todoExecutorRefreshing.value) return;
|
||||
todoExecutorRefreshing.value = true;
|
||||
try {
|
||||
await Promise.all([loadStaffList(), loadTodoTeams()]);
|
||||
} finally {
|
||||
todoExecutorRefreshing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function selectTodoExecutor(member, team) {
|
||||
const entry = todoExecutorTarget.value;
|
||||
if (!entry?.todoConfig) return;
|
||||
@ -963,6 +1086,10 @@ function validateEntries() {
|
||||
if (entry.isPackage) {
|
||||
if (!Number(entry.usageCount) || Number(entry.usageCount) <= 0) return `${entry.packageName}数量必须大于0`;
|
||||
if (!Number.isFinite(Number(entry.discount)) || Number(entry.discount) < 0 || Number(entry.discount) > 10) return `${entry.packageName}折扣需在0到10之间`;
|
||||
if (!entry.enableDiscount && Number(entry.discount) !== 10) return `${entry.packageName}不支持折扣`;
|
||||
if (entry.enableDiscount && Number(entry.discount) < getDiscountMin(entry)) {
|
||||
return `${entry.packageName}折扣不能低于${getDiscountMin(entry)}折`;
|
||||
}
|
||||
if (entry.packageType === "free" && entry.selectedCount !== entry.projectNumber) {
|
||||
return `${entry.packageName}需要选择${entry.projectNumber}项,当前已选择${entry.selectedCount}项`;
|
||||
}
|
||||
@ -979,6 +1106,11 @@ function validateEntries() {
|
||||
if (!entry.project?._id) return `${label}请选择项目`;
|
||||
if (Number(entry.price) < 0 || Number.isNaN(Number(entry.price))) return `${label}价格不能小于0`;
|
||||
if (!Number.isFinite(Number(entry.discount)) || Number(entry.discount) < 0 || Number(entry.discount) > 10) return `${label}折扣需在0到10之间`;
|
||||
if (!entry.isDiscount && Number(entry.discount) !== 10) return `${label}不支持折扣`;
|
||||
if (entry.isDiscount && Number(entry.discount) < getDiscountMin(entry)) {
|
||||
return `${label}折扣不能低于${getDiscountMin(entry)}折`;
|
||||
}
|
||||
if (!entry.isGift && entry.isFree) return `${label}不支持赠送`;
|
||||
if (!Number.isFinite(Number(entry.totalPrice)) || Number(entry.totalPrice) < 0) return `${label}总价不能小于0`;
|
||||
if (!Number(entry.usageCount) || Number(entry.usageCount) <= 0) return `${label}数量必须大于0`;
|
||||
if (!entry.dept?._id) return `${label}请选择治疗科室`;
|
||||
@ -1396,16 +1528,58 @@ async function submitEntries() {
|
||||
}
|
||||
|
||||
.todo-executor-picker {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: var(--keyboard-height);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
max-height: 72vh;
|
||||
height: 72vh;
|
||||
max-height: calc(100vh - var(--keyboard-height));
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 24rpx;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.todo-executor-search {
|
||||
flex: 0 0 64rpx;
|
||||
width: 100%;
|
||||
height: 64rpx;
|
||||
min-height: 64rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin: 20rpx 0;
|
||||
padding: 0 20rpx;
|
||||
border-radius: 10rpx;
|
||||
background: #f5f6f8;
|
||||
}
|
||||
|
||||
.todo-executor-search-input {
|
||||
display: block;
|
||||
flex: 1;
|
||||
width: 0;
|
||||
height: 64rpx;
|
||||
min-height: 64rpx;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 28rpx;
|
||||
line-height: 64rpx;
|
||||
}
|
||||
|
||||
.todo-executor-list {
|
||||
max-height: 58vh;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: auto;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.todo-team-group {
|
||||
@ -1517,6 +1691,15 @@ async function submitEntries() {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.discount-picker {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.discount-picker .number-input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.field-row {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
@ -1663,15 +1846,24 @@ async function submitEntries() {
|
||||
.picker-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
z-index: 999;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.project-picker {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: var(--keyboard-height);
|
||||
width: 100%;
|
||||
max-height: 75vh;
|
||||
height: 75vh;
|
||||
max-height: calc(100vh - var(--keyboard-height));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
padding: 24rpx;
|
||||
@ -1691,6 +1883,11 @@ async function submitEntries() {
|
||||
}
|
||||
|
||||
.search-box {
|
||||
flex: 0 0 64rpx;
|
||||
width: 100%;
|
||||
height: 64rpx;
|
||||
min-height: 64rpx;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
@ -1701,13 +1898,25 @@ async function submitEntries() {
|
||||
}
|
||||
|
||||
.search-input {
|
||||
display: block;
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
width: 0;
|
||||
height: 64rpx;
|
||||
min-height: 64rpx;
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 28rpx;
|
||||
line-height: 64rpx;
|
||||
}
|
||||
|
||||
.project-list {
|
||||
max-height: 55vh;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
height: auto;
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.picker-group-title {
|
||||
|
||||
@ -311,10 +311,11 @@ const env = __VITE_ENV__;
|
||||
const corpId = env.MP_CORP_ID || "";
|
||||
|
||||
// 获取登录状态
|
||||
const accountStore = useAccountStore();
|
||||
const { account, openid, isIMInitialized, doctorInfo } = storeToRefs(
|
||||
useAccountStore()
|
||||
accountStore
|
||||
);
|
||||
const { initIMAfterLogin } = useAccountStore();
|
||||
const { getDoctorInfo, initIMAfterLogin } = accountStore;
|
||||
|
||||
// 聊天输入组件引用
|
||||
const chatInputRef = ref(null);
|
||||
@ -924,7 +925,7 @@ const handleScrollToUpper = async () => {
|
||||
};
|
||||
|
||||
// 页面显示
|
||||
onShow(() => {
|
||||
onShow(async () => {
|
||||
if (!account.value || !openid.value) {
|
||||
uni.redirectTo({
|
||||
url: "/pages-center/login/login",
|
||||
@ -932,6 +933,9 @@ onShow(() => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 每次进入会话页重新获取医生信息,及时同步管理端变更的权益权限。
|
||||
await getDoctorInfo();
|
||||
|
||||
if (!isIMInitialized.value) {
|
||||
checkLoginAndInitTIM();
|
||||
} else if (timChatManager.tim && !timChatManager.isLoggedIn) {
|
||||
|
||||
@ -12,6 +12,7 @@ const urlsConfig = {
|
||||
getTeamData: 'getTeamData',
|
||||
getTeamById: 'getTeamById',
|
||||
getTeamBymember: 'getTeamBymember',
|
||||
getAllTeamByCorp: 'getAllTeamByCorp',
|
||||
getCurrentTemplate: 'getCurrentTemplate',
|
||||
getTemplateGroup: 'getTemplateGroup',
|
||||
getTemplateListByTemptype: 'getTemplateListByTemptype',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user