737 lines
20 KiB
Vue
737 lines
20 KiB
Vue
<template>
|
||
<!-- Mobile 来源: ykt-management-mobile/src/pages/customer/new-followup/new-followup.vue(wxapp:仅新增“待办”任务) -->
|
||
<view class="page">
|
||
<scroll-view scroll-y class="scroll" :style="{ height: scrollHeight + 'px' }">
|
||
<view class="card">
|
||
<picker mode="date" :value="form.planExecutionTime" @change="changeDate">
|
||
<view class="row clickable">
|
||
<view class="left">
|
||
<view class="label">回访日期</view>
|
||
<view class="req">*</view>
|
||
</view>
|
||
<view class="right">
|
||
<view class="value" :class="{ muted: !form.planExecutionTime }">{{ form.planExecutionTime || '请选择回访日期' }}</view>
|
||
<uni-icons type="arrowright" size="16" color="#999" />
|
||
</view>
|
||
</view>
|
||
</picker>
|
||
|
||
<view class="row clickable" @click="selectExecutor">
|
||
<view class="left">
|
||
<view class="label">处理人</view>
|
||
<view class="req">*</view>
|
||
</view>
|
||
<view class="right">
|
||
<view class="value" :class="{ muted: !form.executorName }">
|
||
{{ form.executorName ? `${form.executorName}${form.executeTeamName ? `(${form.executeTeamName})` : ''}` : '请选择处理人' }}
|
||
</view>
|
||
<uni-icons type="arrowright" size="16" color="#999" />
|
||
</view>
|
||
</view>
|
||
|
||
<view class="row clickable" @click="selectType">
|
||
<view class="left">
|
||
<view class="label">类型</view>
|
||
<view class="req">*</view>
|
||
</view>
|
||
<view class="right">
|
||
<view class="value" :class="{ muted: !form.eventType }">{{ eventTypeLabel || '请选择类型' }}</view>
|
||
<uni-icons type="arrowright" size="16" color="#999" />
|
||
</view>
|
||
</view>
|
||
|
||
<view class="block">
|
||
<view class="block-title">目的</view>
|
||
<view class="textarea-box">
|
||
<textarea v-model="form.taskContent" class="textarea" placeholder="请输入文字提醒" maxlength="200" />
|
||
<view class="counter">{{ (form.taskContent || '').length }}/200</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="block">
|
||
<view class="block-title">向患者发送</view>
|
||
<view class="textarea-box">
|
||
<textarea v-model="form.sendContent" class="textarea" placeholder="请输入要发送给患者的内容" maxlength="200" />
|
||
<view class="counter">{{ (form.sendContent || '').length }}/200</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="row clickable" @click="chooseFile">
|
||
<view class="left">
|
||
<view class="label">添加附件</view>
|
||
</view>
|
||
<view class="right">
|
||
<uni-icons type="plusempty" size="16" color="#0877F1" />
|
||
</view>
|
||
</view>
|
||
|
||
<view v-if="showFileList.length" class="file-list">
|
||
<view v-for="(i, index) in showFileList" :key="String(i._k || index)" class="file-item">
|
||
<view class="file-main">
|
||
<view v-if="i.typeStr" class="file-type">{{ i.typeStr }}</view>
|
||
<view class="file-name">{{ i.fileName }}</view>
|
||
</view>
|
||
<uni-icons type="closeempty" size="18" color="#999" @click="removeFile(index)" />
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="scroll-spacer" />
|
||
</scroll-view>
|
||
|
||
<view class="footer">
|
||
<button class="btn plain" @click="cancel">取消</button>
|
||
<button class="btn primary" @click="save">保存</button>
|
||
</view>
|
||
|
||
<uni-popup ref="typePopup" type="bottom" :mask-click="true">
|
||
<view class="picker-sheet">
|
||
<view class="picker-title">选择类型</view>
|
||
<scroll-view scroll-y class="picker-body">
|
||
<view
|
||
v-for="t in eventTypeList"
|
||
:key="t.value"
|
||
class="picker-item"
|
||
:class="{ active: form.eventType === t.value }"
|
||
@click="pickType(t.value)"
|
||
>
|
||
<view class="picker-item-text">{{ t.label }}</view>
|
||
</view>
|
||
</scroll-view>
|
||
<view class="picker-actions">
|
||
<button class="btn plain" @click="closeTypePicker">取消</button>
|
||
<button class="btn primary" @click="closeTypePicker">确定</button>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
|
||
<uni-popup ref="executorPopup" type="bottom" :mask-click="true">
|
||
<view class="picker-sheet">
|
||
<view class="picker-title">选择处理人(本团队)</view>
|
||
<scroll-view scroll-y class="picker-body">
|
||
<view
|
||
v-for="m in teamMembers"
|
||
:key="String(m?.userid || '')"
|
||
class="picker-item"
|
||
:class="{ active: form.executorUserId && String(m?.userid || '') === form.executorUserId }"
|
||
@click="pickExecutor(m)"
|
||
>
|
||
<view class="picker-item-text">{{ String(m?.anotherName || m?.name || m?.userid || '') }}</view>
|
||
</view>
|
||
</scroll-view>
|
||
<view class="picker-actions">
|
||
<button class="btn plain" @click="closeExecutorPicker">取消</button>
|
||
<button class="btn primary" @click="closeExecutorPicker">确定</button>
|
||
</view>
|
||
</view>
|
||
</uni-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, reactive, ref } from 'vue';
|
||
import { onLoad } from '@dcloudio/uni-app';
|
||
import dayjs from 'dayjs';
|
||
import { storeToRefs } from 'pinia';
|
||
import api from '@/utils/api';
|
||
import useAccountStore from '@/store/account';
|
||
import { toast } from '@/utils/widget';
|
||
import { getTodoEventTypeLabel, getTodoEventTypeOptions } from '@/utils/todo-const';
|
||
import { chooseAndUploadImage } from '@/utils/file';
|
||
|
||
const archiveId = ref('');
|
||
const archiveName = ref('');
|
||
const customerData = ref({});
|
||
const scrollHeight = ref(0);
|
||
|
||
// 新增回访任务:仅展示以下 6 种类型
|
||
// 诊后回访、术后回访、就诊提醒、用药提醒、未到院回访、其他
|
||
// 其余类型不删除,仅在该页面隐藏(仍保留在 utils/todo-const.js):
|
||
// followUpNoDeal(未成交回访)、followUpPostTreatment(治疗后回访)、followUpReminder(复诊提醒)、
|
||
// serviceSummary(咨询服务)、eventNotification(活动通知)、ContentReminder(宣教发送)、
|
||
// questionnaire(问卷调查)、followUpComplaint(投诉回访)、followUpActivity(活动回访)
|
||
const __ALL_TODO_EVENT_TYPE_OPTIONS__ = getTodoEventTypeOptions();
|
||
const __NEW_FOLLOWUP_EVENT_TYPE_VALUES__ = [
|
||
'followUp',
|
||
'followUpPostSurgery',
|
||
'appointmentReminder',
|
||
'medicationReminder',
|
||
'followUpNoShow',
|
||
'other',
|
||
];
|
||
const eventTypeList = __NEW_FOLLOWUP_EVENT_TYPE_VALUES__
|
||
.map((v) => __ALL_TODO_EVENT_TYPE_OPTIONS__.find((i) => i.value === v))
|
||
.filter(Boolean);
|
||
|
||
const accountStore = useAccountStore();
|
||
const { account, doctorInfo } = storeToRefs(accountStore);
|
||
const { getDoctorInfo } = accountStore;
|
||
|
||
const teamMembers = ref([]);
|
||
|
||
const form = reactive({
|
||
planExecutionTime: '',
|
||
executeTeamId: '', // teamId
|
||
executeTeamName: '', // teamName
|
||
executorUserId: '', // userid
|
||
executorName: '', // anotherName
|
||
eventType: '',
|
||
taskContent: '',
|
||
sendContent: '',
|
||
fileList: [],
|
||
});
|
||
|
||
const eventTypeLabel = computed(() => getTodoEventTypeLabel(form.eventType));
|
||
|
||
onLoad((options) => {
|
||
resetForm();
|
||
scrollHeight.value = Number(uni.getSystemInfoSync()?.windowHeight || 0) || 0;
|
||
archiveId.value = options?.archiveId ? String(options.archiveId) : '';
|
||
const c = uni.getStorageSync('new-followup-customer');
|
||
if (c && typeof c === 'object') {
|
||
archiveId.value = archiveId.value || String(c._id || '');
|
||
archiveName.value = String(c.name || '');
|
||
customerData.value = c;
|
||
}
|
||
if (!archiveId.value) {
|
||
uni.showToast({ title: '缺少 archiveId', icon: 'none' });
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
return;
|
||
}
|
||
|
||
const cached = uni.getStorageSync('ykt_case_archive_detail');
|
||
if (cached && typeof cached === 'object' && String(cached?._id || '') === archiveId.value) {
|
||
customerData.value = cached;
|
||
archiveName.value = archiveName.value || String(cached.name || '');
|
||
}
|
||
|
||
if (!form.planExecutionTime) form.planExecutionTime = dayjs().add(1, 'day').format('YYYY-MM-DD');
|
||
|
||
initDefaultExecutor();
|
||
});
|
||
|
||
function resetForm(keepCustomer = false) {
|
||
form.planExecutionTime = '';
|
||
form.executeTeamId = '';
|
||
form.executeTeamName = '';
|
||
form.executorUserId = '';
|
||
form.executorName = '';
|
||
form.eventType = '';
|
||
form.taskContent = '';
|
||
form.sendContent = '';
|
||
form.fileList = [];
|
||
if (!keepCustomer) {
|
||
archiveId.value = '';
|
||
archiveName.value = '';
|
||
customerData.value = {};
|
||
}
|
||
teamMembers.value = [];
|
||
uni.setStorageSync('select-mamagement-plan', '');
|
||
}
|
||
|
||
const QUESTIONNAIRE_ICON =
|
||
'https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/19-%E9%97%AE%E5%8D%B7.png?sign=55a4cd77c418b2c548b65792a2cf6bce&t=1701328694';
|
||
const ARTICLE_ICON =
|
||
'https://796f-youcan-clouddev-1-8ewcqf31dbb2b5-1317294507.tcb.qcloud.la/other/18-%E5%AE%A3%E6%95%99.png?sign=26f221d14fd57a2ff0a106dfb01a5e7a&t=1701328694';
|
||
|
||
const showFileList = computed(() =>
|
||
(Array.isArray(form.fileList) ? form.fileList : []).map((i, idx) => {
|
||
const type = i?.type;
|
||
const fileType = i?.file && typeof i.file.type === 'string' ? i.file.type : '';
|
||
let typeStr = '';
|
||
if (type === 'image' || fileType.includes('image')) typeStr = '【图片】';
|
||
else if (type === 'video' || fileType.includes('video')) typeStr = '【视频】';
|
||
else if (fileType === 'article') typeStr = '【文章】';
|
||
else if (fileType === 'questionnaire') typeStr = '【问卷】';
|
||
else if (type === 'link') typeStr = '【链接】';
|
||
|
||
const fileName =
|
||
String(i?.file?.name || i?.file?.title || i?.name || i?.URL || '').trim() ||
|
||
`附件${idx + 1}`;
|
||
|
||
return {
|
||
...i,
|
||
_k: `${idx}_${String(i?.type || '')}_${String(i?.URL || '')}`,
|
||
typeStr,
|
||
fileName,
|
||
};
|
||
})
|
||
);
|
||
|
||
async function ensureDoctor() {
|
||
if (doctorInfo.value) return;
|
||
if (!account.value?.openid) return;
|
||
try {
|
||
await getDoctorInfo();
|
||
} catch {
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
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 = uni.getStorageSync('ykt_case_current_team') || {};
|
||
const a = account.value || {};
|
||
const d = doctorInfo.value || {};
|
||
return String(t.corpId || a.corpId || d.corpId || '') || '';
|
||
}
|
||
|
||
async function loadTeamMembers(teamId) {
|
||
const corpId = getCorpId();
|
||
if (!corpId || !teamId) return;
|
||
const res = await api('getTeamData', { corpId, teamId });
|
||
if (!res?.success) {
|
||
teamMembers.value = [];
|
||
return;
|
||
}
|
||
const t = res?.data && typeof res.data === 'object' ? res.data : {};
|
||
teamMembers.value = Array.isArray(t.memberList) ? t.memberList : [];
|
||
}
|
||
|
||
async function initDefaultExecutor() {
|
||
await ensureDoctor();
|
||
const userId = getUserId();
|
||
const name = String(doctorInfo.value?.anotherName || doctorInfo.value?.name || '');
|
||
const currentTeam = uni.getStorageSync('ykt_case_current_team') || {};
|
||
const teamId = String(currentTeam.teamId || '');
|
||
const teamName = String(currentTeam.name || '');
|
||
if (teamId) {
|
||
form.executeTeamId = teamId;
|
||
form.executeTeamName = teamName;
|
||
await loadTeamMembers(teamId);
|
||
}
|
||
if (userId) {
|
||
form.executorUserId = userId;
|
||
form.executorName = name || '我';
|
||
}
|
||
}
|
||
|
||
function changeDate(e) {
|
||
const date = String(e.detail.value || '');
|
||
if (dayjs().startOf('day').isAfter(dayjs(date))) {
|
||
uni.showToast({ title: '请选择有效的回访日期', icon: 'none' });
|
||
return;
|
||
}
|
||
form.planExecutionTime = date;
|
||
}
|
||
|
||
function selectType() {
|
||
typePopup.value?.open?.();
|
||
}
|
||
|
||
function selectExecutor() {
|
||
if (!teamMembers.value.length) return toast('当前团队暂无可选成员');
|
||
executorPopup.value?.open?.();
|
||
}
|
||
|
||
function cancel() {
|
||
uni.showModal({
|
||
title: '确认取消',
|
||
content: '确定要取消新建回访任务吗?',
|
||
success: (res) => res.confirm && uni.navigateBack(),
|
||
});
|
||
}
|
||
|
||
async function save() {
|
||
if (!form.planExecutionTime) return uni.showToast({ title: '请选择回访日期', icon: 'none' });
|
||
if (!form.executeTeamId) return uni.showToast({ title: '请选择处理人', icon: 'none' });
|
||
if (!form.executorUserId) return uni.showToast({ title: '请选择处理人', icon: 'none' });
|
||
if (!form.eventType) return uni.showToast({ title: '请选择类型', icon: 'none' });
|
||
|
||
await ensureDoctor();
|
||
const corpId = getCorpId();
|
||
const userId = getUserId();
|
||
if (!corpId || !userId) {
|
||
toast('缺少用户/团队信息,请先完成登录与团队选择');
|
||
return;
|
||
}
|
||
const customer = customerData.value && typeof customerData.value === 'object' ? customerData.value : {};
|
||
const customerId = String(customer._id || archiveId.value || '');
|
||
const customerName = String(customer.name || archiveName.value || '');
|
||
const customerUserId = String(customer.externalUserId || customer.customerUserId || '') || '';
|
||
|
||
const enableSend = !!(String(form.sendContent || '').trim() || (Array.isArray(form.fileList) && form.fileList.length));
|
||
const fileList = Array.isArray(form.fileList) ? form.fileList : [];
|
||
|
||
const params = {
|
||
corpId,
|
||
customerId,
|
||
customerName,
|
||
customerUserId,
|
||
executeTeamId: form.executeTeamId,
|
||
executeTeamName: form.executeTeamName,
|
||
creatorUserId: userId,
|
||
userId: form.executorUserId || userId,
|
||
taskList: [
|
||
{
|
||
enableSend,
|
||
eventType: form.eventType,
|
||
executeMethod: 'todo',
|
||
executorUserId: form.executorUserId || userId,
|
||
planExecutionTime: form.planExecutionTime,
|
||
sendContent: String(form.sendContent || ''),
|
||
taskContent: form.taskContent,
|
||
taskId: `${Date.now()}_${Math.random().toString(16).slice(2)}`,
|
||
fileList,
|
||
},
|
||
],
|
||
};
|
||
|
||
const res = await api('executeManagementPlanTodo', params);
|
||
if (!res?.success) {
|
||
toast(res?.message || '保存失败');
|
||
return;
|
||
}
|
||
uni.$emit('archive-detail:followup-changed');
|
||
toast('保存成功');
|
||
setTimeout(() => uni.navigateBack(), 300);
|
||
}
|
||
|
||
const typePopup = ref(null);
|
||
function pickType(v) {
|
||
form.eventType = String(v || '');
|
||
}
|
||
function closeTypePicker() {
|
||
typePopup.value?.close?.();
|
||
}
|
||
|
||
const executorPopup = ref(null);
|
||
function pickExecutor(m) {
|
||
const id = String(m?.userid || '');
|
||
if (!id) return;
|
||
form.executorUserId = id;
|
||
form.executorName = String(m?.anotherName || m?.name || m?.userid || '') || '';
|
||
}
|
||
function closeExecutorPicker() {
|
||
executorPopup.value?.close?.();
|
||
}
|
||
|
||
function removeFile(index) {
|
||
if (!Array.isArray(form.fileList)) form.fileList = [];
|
||
form.fileList.splice(index, 1);
|
||
}
|
||
|
||
function chooseFile() {
|
||
uni.showActionSheet({
|
||
itemList: ['图片', '文章', '问卷'],
|
||
success: ({ tapIndex }) => {
|
||
if (tapIndex === 0) chooseImage();
|
||
else if (tapIndex === 1) chooseArticle();
|
||
else if (tapIndex === 2) chooseQuestionnaire();
|
||
},
|
||
});
|
||
}
|
||
|
||
async function chooseImage() {
|
||
const url = await chooseAndUploadImage({ count: 1 });
|
||
if (!url) return;
|
||
form.fileList.push({
|
||
type: 'image',
|
||
URL: url,
|
||
file: {
|
||
type: 'image',
|
||
name: `图片_${dayjs().format('MMDD_HHmmss')}.jpg`,
|
||
},
|
||
});
|
||
}
|
||
|
||
function chooseArticle() {
|
||
const eventName = `on-select-article_${Date.now()}`;
|
||
uni.navigateTo({
|
||
url: `/pages/message/article-list?select=1&eventName=${eventName}`,
|
||
});
|
||
uni.$once(eventName, (data) => {
|
||
const corpId = getCorpId();
|
||
const articleId = String(data?._id || data?.id || '');
|
||
if (!articleId) return;
|
||
const url = `${__VITE_ENV__?.MP_PATIENT_PAGE_BASE_URL || ''}pages/article/index?id=${articleId}&corpId=${corpId}`;
|
||
form.fileList.push({
|
||
type: 'link',
|
||
URL: String(data?.cover || data?.imgUrl || '') || ARTICLE_ICON,
|
||
file: {
|
||
type: 'article',
|
||
name: String(data?.title || '宣教文章'),
|
||
subtitle: String(data?.summary || data?.desc || ''),
|
||
url,
|
||
},
|
||
});
|
||
});
|
||
}
|
||
|
||
function chooseQuestionnaire() {
|
||
const eventName = `on-select-survey_${Date.now()}`;
|
||
uni.navigateTo({
|
||
url: `/pages/message/survey-list?select=1&eventName=${eventName}&patientId=${archiveId.value}&customerName=${archiveName.value || ''}`,
|
||
});
|
||
uni.$once(eventName, (data) => {
|
||
const corpId = getCorpId();
|
||
const surveryId = String(data?._id || data?.surveryId || '');
|
||
if (!surveryId) return;
|
||
const url = `${__VITE_ENV__?.MP_PATIENT_PAGE_BASE_URL || ''}pages/survery/fill?corpId=${corpId}&surveryId=${surveryId}`;
|
||
form.fileList.push({
|
||
type: 'link',
|
||
URL: QUESTIONNAIRE_ICON,
|
||
file: {
|
||
type: 'questionnaire',
|
||
name: String(data?.name || '问卷'),
|
||
surveryId,
|
||
url,
|
||
},
|
||
});
|
||
});
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page {
|
||
height: 100vh;
|
||
background: #f5f6f8;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.scroll-spacer {
|
||
height: calc(76px + env(safe-area-inset-bottom));
|
||
}
|
||
.card {
|
||
background: #fff;
|
||
margin: 10px 14px 0;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
|
||
}
|
||
.row {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 14px 14px;
|
||
border-bottom: 1px solid #f2f2f2;
|
||
}
|
||
.row.clickable:active {
|
||
background: #fafafa;
|
||
}
|
||
.left {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.label {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
.req {
|
||
margin-left: 6px;
|
||
color: #ff4d4f;
|
||
font-size: 14px;
|
||
}
|
||
.right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
.value {
|
||
font-size: 14px;
|
||
color: #333;
|
||
max-width: 220px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
.value.muted {
|
||
color: #999;
|
||
}
|
||
.block {
|
||
padding: 14px 14px;
|
||
border-bottom: 1px solid #f2f2f2;
|
||
}
|
||
.block:last-child {
|
||
border-bottom: none;
|
||
}
|
||
.block-title {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-bottom: 10px;
|
||
}
|
||
.picker-sheet {
|
||
background: #fff;
|
||
border-top-left-radius: 10px;
|
||
border-top-right-radius: 10px;
|
||
overflow: hidden;
|
||
}
|
||
.picker-title {
|
||
text-align: center;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
padding: 14px;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
.picker-body {
|
||
max-height: 60vh;
|
||
}
|
||
.picker-item {
|
||
padding: 14px;
|
||
border-bottom: 1px solid #f2f2f2;
|
||
}
|
||
.picker-item.active {
|
||
background: #f2f6ff;
|
||
}
|
||
.picker-item-text {
|
||
font-size: 14px;
|
||
color: #333;
|
||
}
|
||
.picker-actions {
|
||
padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
|
||
display: flex;
|
||
gap: 12px;
|
||
background: #fff;
|
||
}
|
||
.textarea-box {
|
||
border: 1px solid #e6e6e6;
|
||
border-radius: 8px;
|
||
padding: 10px;
|
||
}
|
||
.textarea {
|
||
width: 100%;
|
||
min-height: 90px;
|
||
font-size: 14px;
|
||
box-sizing: border-box;
|
||
}
|
||
.counter {
|
||
margin-top: 6px;
|
||
text-align: right;
|
||
font-size: 12px;
|
||
color: #999;
|
||
}
|
||
.file-list {
|
||
padding: 0 14px 14px;
|
||
}
|
||
.file-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 10px;
|
||
margin-top: 10px;
|
||
padding: 12px 12px;
|
||
background: #f5f6f8;
|
||
border-radius: 8px;
|
||
}
|
||
.file-main {
|
||
display: flex;
|
||
align-items: center;
|
||
min-width: 0;
|
||
gap: 8px;
|
||
}
|
||
.file-type {
|
||
flex-shrink: 0;
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
.file-name {
|
||
font-size: 14px;
|
||
color: #333;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
max-width: 240px;
|
||
}
|
||
.toggle-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
.pill {
|
||
padding: 8px 12px;
|
||
border-radius: 999px;
|
||
background: #eaecef;
|
||
font-size: 12px;
|
||
color: #333;
|
||
}
|
||
.pill.active {
|
||
background: #0877F1;
|
||
color: #fff;
|
||
}
|
||
.info {
|
||
margin-left: auto;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 9px;
|
||
background: #cfd3dc;
|
||
color: #fff;
|
||
font-size: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.footer {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: #fff;
|
||
padding: 12px 14px calc(12px + env(safe-area-inset-bottom));
|
||
display: flex;
|
||
gap: 12px;
|
||
box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
|
||
}
|
||
.btn {
|
||
flex: 1;
|
||
height: 44px;
|
||
line-height: 44px;
|
||
border-radius: 6px;
|
||
font-size: 15px;
|
||
}
|
||
.btn::after {
|
||
border: none;
|
||
}
|
||
.btn.plain {
|
||
background: #fff;
|
||
color: #0877F1;
|
||
border: 1px solid #0877F1;
|
||
}
|
||
.btn.primary {
|
||
background: #0877F1;
|
||
color: #fff;
|
||
}
|
||
|
||
.modal {
|
||
width: 320px;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
.modal-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
text-align: center;
|
||
padding: 14px 12px;
|
||
color: #333;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
.modal-body {
|
||
padding: 14px;
|
||
}
|
||
.modal-text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
line-height: 20px;
|
||
margin-bottom: 10px;
|
||
}
|
||
.modal-actions {
|
||
padding: 12px 14px 14px;
|
||
}
|
||
.modal-btn {
|
||
height: 40px;
|
||
line-height: 40px;
|
||
text-align: center;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
}
|
||
.modal-btn.save {
|
||
background: #0877F1;
|
||
color: #fff;
|
||
}
|
||
</style>
|