646 lines
19 KiB
Vue
646 lines
19 KiB
Vue
<template>
|
|
<div v-can="pageAccess" class="follow-up-reminder-edit">
|
|
<t-form class="form" label-width="6rem">
|
|
<t-form-item label="客户" content-align="right" required-mark>
|
|
<div class="customer-picker">
|
|
<span v-if="!selectedCustomer" class="picker-text" v-text="'请选择客户'" />
|
|
<t-button
|
|
theme="primary"
|
|
size="extra-small"
|
|
content="选择"
|
|
@click="customerSelectorVisible = true"
|
|
/>
|
|
</div>
|
|
</t-form-item>
|
|
<t-form-item v-if="selectedCustomer" label-width="0">
|
|
<customer-profile-card class="customer-profile" :customer="selectedCustomer" />
|
|
</t-form-item>
|
|
<t-form-item
|
|
label="负责人"
|
|
content-align="right"
|
|
required-mark
|
|
arrow
|
|
@click="responsibleSelectorVisible = true"
|
|
>
|
|
<span v-text="selectedResponsibleName" />
|
|
</t-form-item>
|
|
<t-form-item label="跟进内容" required-mark>
|
|
<t-textarea
|
|
v-model="formModel.content"
|
|
class="textarea"
|
|
:autosize="{ minRows: 1, maxRows: 8 }"
|
|
maxlength="1000"
|
|
borderless
|
|
placeholder="请输入跟进内容"
|
|
/>
|
|
</t-form-item>
|
|
<t-form-item label-width="0">
|
|
<media-selector
|
|
:model-value="photoUrlList"
|
|
v-model:photo-items="photoItems"
|
|
:upload="uploadReminderPhotoList"
|
|
:edit-mode="true"
|
|
:loading="isSaving || isUploading"
|
|
add-text="选择照片"
|
|
:show-type-label="false"
|
|
title="附件照片"
|
|
/>
|
|
</t-form-item>
|
|
</t-form>
|
|
<t-form class="form">
|
|
<t-form-item class="remind-at" label="提醒时间" content-align="right" required-mark>
|
|
<span class="picker-text" v-text="formModel.remindAtText || '请选择提醒时间'" />
|
|
</t-form-item>
|
|
<t-form-item label-width="0" content-align="right">
|
|
<t-radio-group
|
|
v-model="selectedRemindAtPreset"
|
|
@change="handleRemindAtPresetChange"
|
|
>
|
|
<t-radio :block="false" borderless value="tomorrow">明天</t-radio>
|
|
<t-radio :block="false" borderless value="afterTomorrow">后天</t-radio>
|
|
<t-radio :block="false" borderless value="custom">指定时间</t-radio>
|
|
</t-radio-group>
|
|
</t-form-item>
|
|
<t-form-item label="站内通知" content-align="right">
|
|
<t-switch
|
|
size="small"
|
|
:model-value="hasChannel('INTERNAL')"
|
|
borderless
|
|
@change="value => setChannel('INTERNAL', value === true)"
|
|
/>
|
|
</t-form-item>
|
|
<t-form-item label="短信通知" content-align="right">
|
|
<t-switch
|
|
size="small"
|
|
:model-value="hasChannel('SMS')"
|
|
:disabled="!canSelectSms"
|
|
borderless
|
|
@change="value => setChannel('SMS', value === true)"
|
|
/>
|
|
</t-form-item>
|
|
</t-form>
|
|
<div class="tips red"
|
|
v-text="'提醒时间精确到分钟,不能早于当前时间。短信会在提醒日期 08:00 聚合发送,不会在你选择的精确时间发送。'" />
|
|
<customer-selector
|
|
v-model="formModel.customerId"
|
|
v-model:visible="customerSelectorVisible"
|
|
:store-id="customerPickerStoreId"
|
|
@change="handleCustomerChange"
|
|
/>
|
|
<managed-user-selector
|
|
v-model="formModel.responsibleUserId"
|
|
v-model:visible="responsibleSelectorVisible"
|
|
:store-id="responsiblePickerStoreId"
|
|
@change="handleResponsibleChange"
|
|
/>
|
|
<t-popup v-model="remindAtPickerVisible" placement="bottom">
|
|
<t-date-time-picker
|
|
v-if="remindAtPickerVisible"
|
|
v-model="remindAtDraftText"
|
|
:start="minimumDateTimeText"
|
|
format="YYYY-MM-DD HH:mm"
|
|
:mode="['date', 'minute']"
|
|
title="提醒时间"
|
|
@cancel="cancelRemindAtPicker"
|
|
@confirm="confirmRemindAt"
|
|
/>
|
|
</t-popup>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { Time } from "timi-web";
|
|
import { AttachmentAPI, type User, useUserStore } from "timi-web-api";
|
|
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
|
|
import { Message } from "@/utils/message";
|
|
import { getErrorMessage } from "@/utils/error";
|
|
import FollowUpReminderAPI from "@/api/FollowUpReminderAPI";
|
|
import CustomerAPI from "@/api/CustomerAPI";
|
|
import CustomerSelector from "@/components/CustomerSelector.vue";
|
|
import ManagedUserSelector from "@/pages/followUpReminder/component/ManagedUserSelector.vue";
|
|
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
|
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
|
import { useNavBarStore } from "@/store/navBarStore";
|
|
import type { Customer } from "@/types/Customer";
|
|
import type { ManagedUser } from "@/types/ManagedUser";
|
|
import type {
|
|
FollowUpReminder,
|
|
FollowUpReminderAttachment,
|
|
FollowUpReminderNotifyChannel,
|
|
FollowUpReminderPayload
|
|
} from "@/types/FollowUpReminder";
|
|
import type { PhotoItem } from "@/types/Photo";
|
|
import { compressUploadImageList } from "@/utils/imageCompression";
|
|
import { getAttachmentReadURL } from "@/utils/attachment";
|
|
import { parseDateTime } from "@/utils/date";
|
|
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
|
|
|
defineOptions({
|
|
name: "FollowUpReminderEdit"
|
|
});
|
|
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const userStore = useUserStore();
|
|
const currentStoreStore = useCurrentStoreStore();
|
|
const navBarStore = useNavBarStore();
|
|
|
|
const routeId = computed(() => String(route.params.id || ""));
|
|
const isEditMode = computed(() => !!routeId.value);
|
|
const pageAccess = computed(() => isEditMode.value
|
|
? permissionCodes.customerFollowUpReminder.update
|
|
: permissionCodes.customerFollowUpReminder.create);
|
|
|
|
// ---------- 表单 ----------
|
|
|
|
const isSaving = ref(false);
|
|
const formModel = reactive({
|
|
id: "",
|
|
storeId: "",
|
|
customerId: "",
|
|
responsibleUserId: "",
|
|
content: "",
|
|
remindAtText: "",
|
|
notifyChannelList: [] as FollowUpReminderNotifyChannel[]
|
|
});
|
|
const selectedCustomer = ref<Customer>();
|
|
const selectedResponsible = ref<ManagedUser>();
|
|
const photoItems = ref<PhotoItem[]>([]);
|
|
const photoUrlList = computed(() => photoItems.value.map(item => item.previewUrl || item.url));
|
|
const customerSelectorVisible = ref(false);
|
|
const responsibleSelectorVisible = ref(false);
|
|
const customerPickerStoreId = computed(() => formModel.storeId || currentStoreStore.currentStoreId);
|
|
const responsiblePickerStoreId = computed(() => selectedCustomer.value?.storeId || customerPickerStoreId.value);
|
|
const currentUserId = computed(() => userStore.loginUser.user?.id || userStore.loginUser.id || "");
|
|
const selectedResponsibleName = computed(() => {
|
|
if (!selectedResponsible.value) {
|
|
return "请选择负责人";
|
|
}
|
|
if (selectedResponsible.value.userId === currentUserId.value) {
|
|
return "本人";
|
|
}
|
|
return getResponsibleName(selectedResponsible.value);
|
|
});
|
|
|
|
// ---------- 通知方式 ----------
|
|
|
|
const hasSmsChannel = computed(() => hasChannel("SMS"));
|
|
const isTodayReminder = computed(() => {
|
|
const remindAt = parseRemindAt();
|
|
if (!remindAt) {
|
|
return false;
|
|
}
|
|
return Time.formatDate(new Date(remindAt)) === Time.formatDate(new Date(Time.now()));
|
|
});
|
|
const isBeforeSmsCutoff = computed(() => {
|
|
const now = new Date(Time.now());
|
|
return now.getHours() < 8;
|
|
});
|
|
const canSelectSms = computed(() => isResponsiblePhoneValid(selectedResponsible.value)
|
|
&& (!isTodayReminder.value || isBeforeSmsCutoff.value));
|
|
const smsRuleText = computed(() => {
|
|
if (!selectedResponsible.value) {
|
|
return "短信通知要求负责人有有效的已验证手机号。";
|
|
}
|
|
if (!isResponsiblePhoneValid(selectedResponsible.value)) {
|
|
return "当前负责人没有有效的已验证手机号,短信通知不可用。";
|
|
}
|
|
if (isTodayReminder.value && !isBeforeSmsCutoff.value) {
|
|
return "今天 08:00 后创建今天的提醒不能选择短信通知。";
|
|
}
|
|
return "短信将在提醒日期 08:00 聚合发送,允许与站内通知同时选择。";
|
|
});
|
|
|
|
function hasChannel(channel: FollowUpReminderNotifyChannel): boolean {
|
|
return formModel.notifyChannelList.includes(channel);
|
|
}
|
|
|
|
function setChannel(channel: FollowUpReminderNotifyChannel, checked: boolean): void {
|
|
if (channel === "SMS" && checked && !canSelectSms.value) {
|
|
Message.warning(smsRuleText.value);
|
|
return;
|
|
}
|
|
const channelSet = new Set(formModel.notifyChannelList);
|
|
if (checked) {
|
|
channelSet.add(channel);
|
|
} else {
|
|
channelSet.delete(channel);
|
|
}
|
|
formModel.notifyChannelList = Array.from(channelSet);
|
|
}
|
|
|
|
function isResponsiblePhoneValid(item?: ManagedUser): boolean {
|
|
const phone = item?.user?.phoneNo;
|
|
return Boolean(phone && item?.user?.phoneNoVerified && /^1\d{10}$/.test(phone));
|
|
}
|
|
|
|
function getResponsibleName(item: ManagedUser): string {
|
|
return item.user?.nick || item.user?.name || item.userId || "未命名负责人";
|
|
}
|
|
|
|
// ---------- 客户和负责人 ----------
|
|
|
|
async function handleCustomerChange(customerId: string): Promise<void> {
|
|
formModel.customerId = customerId;
|
|
selectedCustomer.value = customerId ? await loadCustomer(customerId) : undefined;
|
|
formModel.storeId = selectedCustomer.value?.storeId || currentStoreStore.currentStoreId;
|
|
if (selectedResponsible.value && selectedResponsible.value.storeId !== formModel.storeId) {
|
|
formModel.responsibleUserId = "";
|
|
selectedResponsible.value = undefined;
|
|
setChannel("SMS", false);
|
|
}
|
|
}
|
|
|
|
function handleResponsibleChange(item: ManagedUser): void {
|
|
selectedResponsible.value = item;
|
|
formModel.responsibleUserId = item.userId || "";
|
|
if (isResponsiblePhoneValid(item) && canSelectSms.value) {
|
|
setChannel("SMS", true);
|
|
}
|
|
}
|
|
|
|
function selectCurrentUser(): void {
|
|
if (!currentUserId.value) {
|
|
Message.warning("当前登录用户信息不可用");
|
|
return;
|
|
}
|
|
handleResponsibleChange({
|
|
storeId: responsiblePickerStoreId.value,
|
|
userId: currentUserId.value,
|
|
enabled: true,
|
|
user: userStore.loginUser.user as Partial<User> | undefined
|
|
});
|
|
}
|
|
|
|
async function loadCustomer(customerId: string): Promise<Customer | undefined> {
|
|
try {
|
|
return await CustomerAPI.detail(customerId);
|
|
} catch {
|
|
Message.warning("客户详情加载失败");
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
// ---------- 时间 ----------
|
|
|
|
type RemindAtPreset = "tomorrow" | "afterTomorrow" | "custom";
|
|
|
|
const selectedRemindAtPreset = ref<RemindAtPreset>("tomorrow");
|
|
const remindAtPickerVisible = ref(false);
|
|
const remindAtDraftText = ref("");
|
|
const minimumDateTimeText = computed(() => {
|
|
const date = new Date(Time.now());
|
|
date.setSeconds(0, 0);
|
|
date.setMinutes(date.getMinutes() + 1);
|
|
return Time.formatDateTime(date);
|
|
});
|
|
|
|
function getQuickRemindAt(dayOffset: number): string {
|
|
const date = new Date(Time.now());
|
|
date.setSeconds(0, 0);
|
|
date.setDate(date.getDate() + dayOffset);
|
|
return Time.formatDateTime(date);
|
|
}
|
|
|
|
function getQuickRemindDate(dayOffset: number): string {
|
|
const date = new Date(Time.now());
|
|
date.setDate(date.getDate() + dayOffset);
|
|
return Time.formatDate(date);
|
|
}
|
|
|
|
function getRemindAtPreset(value: string): RemindAtPreset {
|
|
const remindAt = Time.toTimestamp(parseDateTime(value, false));
|
|
if (!remindAt) {
|
|
return "tomorrow";
|
|
}
|
|
const remindDate = Time.formatDate(new Date(remindAt));
|
|
if (remindDate === getQuickRemindDate(1)) {
|
|
return "tomorrow";
|
|
}
|
|
if (remindDate === getQuickRemindDate(2)) {
|
|
return "afterTomorrow";
|
|
}
|
|
return "custom";
|
|
}
|
|
|
|
function selectRemindAtPreset(preset: RemindAtPreset): void {
|
|
selectedRemindAtPreset.value = preset;
|
|
if (preset === "custom") {
|
|
openRemindAtPicker();
|
|
return;
|
|
}
|
|
formModel.remindAtText = getQuickRemindAt(preset === "tomorrow" ? 1 : 2);
|
|
}
|
|
|
|
function handleRemindAtPresetChange(value: string | number | boolean): void {
|
|
if (value !== "tomorrow" && value !== "afterTomorrow" && value !== "custom") {
|
|
return;
|
|
}
|
|
selectRemindAtPreset(value);
|
|
}
|
|
|
|
function openRemindAtPicker(): void {
|
|
remindAtDraftText.value = formModel.remindAtText || minimumDateTimeText.value;
|
|
remindAtPickerVisible.value = true;
|
|
}
|
|
|
|
function cancelRemindAtPicker(): void {
|
|
remindAtPickerVisible.value = false;
|
|
selectedRemindAtPreset.value = getRemindAtPreset(formModel.remindAtText);
|
|
}
|
|
|
|
function confirmRemindAt(value?: string | number): void {
|
|
formModel.remindAtText = String(value || remindAtDraftText.value);
|
|
selectedRemindAtPreset.value = "custom";
|
|
remindAtPickerVisible.value = false;
|
|
}
|
|
|
|
function parseRemindAt(): number | undefined {
|
|
if (!formModel.remindAtText) {
|
|
return undefined;
|
|
}
|
|
return Time.toTimestamp(parseDateTime(formModel.remindAtText, false));
|
|
}
|
|
|
|
// ---------- 附件 ----------
|
|
|
|
const isUploading = ref(false);
|
|
|
|
async function uploadReminderPhotoList(fileList: File[]): Promise<PhotoItem[]> {
|
|
isUploading.value = true;
|
|
try {
|
|
const tempFileList = await AttachmentAPI.upload(await compressUploadImageList(fileList));
|
|
return tempFileList.flatMap((item, index) => {
|
|
if (!item.id) {
|
|
return [];
|
|
}
|
|
return [
|
|
{
|
|
attachment: {
|
|
tempFileId: item.id,
|
|
mimeType: fileList[index]?.type,
|
|
name: fileList[index]?.name,
|
|
title: fileList[index] ? getFileTitle(fileList[index].name) : undefined
|
|
},
|
|
tempFileId: item.id,
|
|
attachType: "PHOTO",
|
|
mimeType: fileList[index]?.type,
|
|
url: AttachmentAPI.getTempReadURL(item.id || "")
|
|
}
|
|
];
|
|
});
|
|
} catch (error) {
|
|
Message.error(getErrorMessage(error, "附件上传失败"));
|
|
return [];
|
|
} finally {
|
|
isUploading.value = false;
|
|
}
|
|
}
|
|
|
|
function getFileTitle(name: string): string {
|
|
return name.replace(/\.[^.]+$/, "");
|
|
}
|
|
|
|
function getAttachmentURL(item: FollowUpReminderAttachment): string {
|
|
if (item.id) {
|
|
return getAttachmentReadURL(item.id);
|
|
}
|
|
if (item.tempFileId) {
|
|
return AttachmentAPI.getTempReadURL(item.tempFileId);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function toPhotoItems(items: readonly FollowUpReminderAttachment[]): PhotoItem[] {
|
|
const result: PhotoItem[] = [];
|
|
for (const item of items) {
|
|
const url = getAttachmentURL(item);
|
|
if (!url) {
|
|
continue;
|
|
}
|
|
result.push({
|
|
attachment: item,
|
|
tempFileId: item.tempFileId,
|
|
attachType: item.attachType || "PHOTO",
|
|
url
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function toAttachmentList(items: readonly PhotoItem[]): FollowUpReminderAttachment[] {
|
|
return items.map(item => ({
|
|
...(item.attachment || {}),
|
|
tempFileId: item.tempFileId || item.attachment?.tempFileId,
|
|
attachType: item.attachType || item.attachment?.attachType || "PHOTO"
|
|
})).filter(item => !!item.id || !!item.tempFileId);
|
|
}
|
|
|
|
// ---------- 加载和保存 ----------
|
|
|
|
async function loadStoreScope(): Promise<void> {
|
|
if (userStore.hasRoles(gaoRoleCodes.globalManager)) {
|
|
await currentStoreStore.loadStoreList();
|
|
formModel.storeId = currentStoreStore.currentStoreId;
|
|
return;
|
|
}
|
|
const store = await currentStoreStore.loadLoginStore();
|
|
formModel.storeId = store?.id || "";
|
|
}
|
|
|
|
async function loadForm(): Promise<void> {
|
|
await loadStoreScope();
|
|
if (!routeId.value) {
|
|
formModel.notifyChannelList = ["INTERNAL"];
|
|
const queryCustomerId = String(route.query.customerId || "");
|
|
if (queryCustomerId) {
|
|
await handleCustomerChange(queryCustomerId);
|
|
}
|
|
selectCurrentUser();
|
|
formModel.remindAtText = getQuickRemindAt(1);
|
|
selectedRemindAtPreset.value = "tomorrow";
|
|
return;
|
|
}
|
|
|
|
const current = await FollowUpReminderAPI.detail(routeId.value);
|
|
if (current.status !== "PENDING") {
|
|
Message.warning("已完成的跟进提醒不能修改");
|
|
await router.replace({ name: "CustomerFollowUpReminderDetail", params: { id: routeId.value } });
|
|
return;
|
|
}
|
|
applyReminder(current);
|
|
}
|
|
|
|
function applyReminder(current: FollowUpReminder): void {
|
|
Object.assign(formModel, {
|
|
id: current.id || "",
|
|
storeId: current.storeId || "",
|
|
customerId: current.customerId || "",
|
|
responsibleUserId: current.responsibleUserId || "",
|
|
content: current.content || "",
|
|
remindAtText: current.remindAt ? Time.formatDateTime(new Date(current.remindAt)) : minimumDateTimeText.value,
|
|
notifyChannelList: current.notifyChannelList || buildChannelList(current)
|
|
});
|
|
selectedCustomer.value = current.customer;
|
|
selectedResponsible.value = current.responsibleUserId
|
|
? {
|
|
storeId: current.storeId,
|
|
userId: current.responsibleUserId,
|
|
enabled: true,
|
|
user: current.responsibleUser as Partial<User> | undefined
|
|
}
|
|
: undefined;
|
|
photoItems.value = toPhotoItems(current.attachmentList || []);
|
|
selectedRemindAtPreset.value = getRemindAtPreset(formModel.remindAtText);
|
|
}
|
|
|
|
function buildChannelList(item: FollowUpReminder): FollowUpReminderNotifyChannel[] {
|
|
const result: FollowUpReminderNotifyChannel[] = [];
|
|
if (item.internalNotifyEnabled) {
|
|
result.push("INTERNAL");
|
|
}
|
|
if (item.smsNotifyEnabled) {
|
|
result.push("SMS");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function validateForm(remindAt?: number): boolean {
|
|
if (!formModel.customerId || !selectedCustomer.value?.id) {
|
|
Message.warning("请选择客户");
|
|
return false;
|
|
}
|
|
if (!formModel.responsibleUserId || !selectedResponsible.value?.userId) {
|
|
Message.warning("请选择负责人");
|
|
return false;
|
|
}
|
|
if (!formModel.content.trim()) {
|
|
Message.warning("请填写跟进内容");
|
|
return false;
|
|
}
|
|
if (!remindAt || !(0 === remindAt % 60000) || !(Time.now() < remindAt)) {
|
|
Message.warning("请选择晚于当前时间的分钟提醒时间");
|
|
return false;
|
|
}
|
|
if (hasSmsChannel.value && !canSelectSms.value) {
|
|
Message.warning(smsRuleText.value);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async function save(): Promise<void> {
|
|
if (isSaving.value || isUploading.value) {
|
|
return;
|
|
}
|
|
const remindAt = parseRemindAt();
|
|
if (!validateForm(remindAt)) {
|
|
return;
|
|
}
|
|
|
|
const payload: FollowUpReminderPayload = {
|
|
id: formModel.id || undefined,
|
|
storeId: formModel.storeId || undefined,
|
|
customerId: formModel.customerId,
|
|
responsibleUserId: formModel.responsibleUserId,
|
|
content: formModel.content.trim(),
|
|
remindAt: remindAt as number,
|
|
notifyChannelList: [...formModel.notifyChannelList],
|
|
attachmentList: toAttachmentList(photoItems.value)
|
|
};
|
|
|
|
isSaving.value = true;
|
|
try {
|
|
let id = formModel.id;
|
|
if (isEditMode.value) {
|
|
await FollowUpReminderAPI.update(payload);
|
|
} else {
|
|
id = await FollowUpReminderAPI.create(payload);
|
|
}
|
|
Message.success("跟进提醒已保存");
|
|
await router.replace({ name: "CustomerFollowUpReminderDetail", params: { id } });
|
|
} catch (error) {
|
|
Message.error(getErrorMessage(error, "跟进提醒保存失败"));
|
|
} finally {
|
|
isSaving.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
navBarStore.setRightText(isEditMode.value ? "保存" : "提交", "var(--td-brand-color)", save);
|
|
try {
|
|
await loadForm();
|
|
} catch (error) {
|
|
Message.error(getErrorMessage(error, "跟进提醒加载失败"));
|
|
}
|
|
});
|
|
|
|
onUnmounted(() => navBarStore.clearRight());
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.follow-up-reminder-edit {
|
|
gap: 1rem;
|
|
display: flex;
|
|
padding: calc(var(--app-nav-height) + 1rem) 0 4rem;
|
|
flex-direction: column;
|
|
|
|
.form {
|
|
border-radius: 1rem;
|
|
|
|
.customer-picker {
|
|
gap: .5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.customer-profile {
|
|
flex: 1;
|
|
}
|
|
|
|
.responsible-picker {
|
|
gap: .5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.textarea {
|
|
width: 100%;
|
|
}
|
|
|
|
.remind-at {
|
|
|
|
&:after {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
.warning {
|
|
color: var(--td-error-color);
|
|
}
|
|
|
|
}
|
|
|
|
.tips {
|
|
margin: 0 2rem;
|
|
font-size: .875rem;
|
|
line-height: 1.5;
|
|
}
|
|
}
|
|
|
|
:global(html.theme-dark) {
|
|
.follow-up-reminder-edit {
|
|
.form {
|
|
.picker-text {
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.textarea {
|
|
background: rgba(15, 23, 42, .72);
|
|
border-color: rgba(148, 163, 184, .16);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|