2026-05-27 16:22:22 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<full-page customScroll pageStyle="background:#f4f5f7">
|
|
|
|
|
|
<template #header>
|
|
|
|
|
|
<view class="search-bar">
|
|
|
|
|
|
<input
|
|
|
|
|
|
v-model="keyword"
|
|
|
|
|
|
class="search-input"
|
|
|
|
|
|
placeholder="搜索"
|
|
|
|
|
|
confirm-type="search"
|
|
|
|
|
|
@input="onSearchInput"
|
|
|
|
|
|
@confirm="loadList"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="template-page">
|
|
|
|
|
|
<scroll-view scroll-y class="category-panel">
|
|
|
|
|
|
<view
|
|
|
|
|
|
v-for="item in categoryList"
|
|
|
|
|
|
:key="item.viewType"
|
|
|
|
|
|
class="category-item"
|
|
|
|
|
|
:class="{ active: activeViewType === item.viewType }"
|
|
|
|
|
|
@click="changeCategory(item.viewType)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<text class="category-text">{{ item.label }}</text>
|
2026-01-22 17:39:23 +08:00
|
|
|
|
</view>
|
2026-05-27 16:22:22 +08:00
|
|
|
|
</scroll-view>
|
|
|
|
|
|
|
|
|
|
|
|
<view class="content-panel">
|
|
|
|
|
|
<view v-if="loading" class="state-text">加载中...</view>
|
|
|
|
|
|
<empty-data v-else-if="list.length === 0" fullCenter :text="emptyText" />
|
|
|
|
|
|
<scroll-view v-else scroll-y class="list-scroll">
|
|
|
|
|
|
<view v-for="p in list" :key="p.id" class="template-card">
|
|
|
|
|
|
<view class="card-header">
|
|
|
|
|
|
<view class="plan-name">{{ p.planName || '--' }}</view>
|
|
|
|
|
|
<view
|
|
|
|
|
|
v-if="canToggleFavorite(p)"
|
|
|
|
|
|
class="favorite-btn"
|
|
|
|
|
|
:class="{ collected: p.isFavorite }"
|
|
|
|
|
|
@click.stop="toggleFavorite(p)"
|
|
|
|
|
|
>
|
|
|
|
|
|
<uni-icons
|
|
|
|
|
|
class="favorite-icon"
|
|
|
|
|
|
:type="p.isFavorite ? 'star-filled' : 'star'"
|
|
|
|
|
|
size="18"
|
|
|
|
|
|
:color="p.isFavorite ? '#1f5cff' : '#667085'"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="creator" v-if="getCreatorText(p)">{{ getCreatorText(p) }}</view>
|
|
|
|
|
|
<view class="card-footer">
|
|
|
|
|
|
<view class="task-link" @click.stop="preview(p)">任务详情 〉</view>
|
|
|
|
|
|
<view class="select-btn" @click="select(p)">选择</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</scroll-view>
|
2026-01-22 17:39:23 +08:00
|
|
|
|
</view>
|
2026-05-27 16:22:22 +08:00
|
|
|
|
</view>
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
|
|
|
|
|
<template #footer>
|
2026-05-27 16:22:22 +08:00
|
|
|
|
<view class="footer">
|
|
|
|
|
|
<view class="service-entry" @click="toService">
|
|
|
|
|
|
<text class="service-muted">如没有符合的内容,请</text>
|
|
|
|
|
|
<text class="service-link">联系客服</text>
|
2026-02-12 14:44:58 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</full-page>
|
2026-01-22 17:39:23 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref } from 'vue';
|
|
|
|
|
|
import { onLoad } from '@dcloudio/uni-app';
|
2026-01-26 15:39:14 +08:00
|
|
|
|
import { storeToRefs } from 'pinia';
|
|
|
|
|
|
import api from '@/utils/api';
|
|
|
|
|
|
import useAccountStore from '@/store/account';
|
|
|
|
|
|
import { toast } from '@/utils/widget';
|
|
|
|
|
|
import { getTodoEventTypeLabel } from '@/utils/todo-const';
|
2026-01-22 17:39:23 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
import EmptyData from '@/components/empty-data.vue';
|
2026-02-12 14:44:58 +08:00
|
|
|
|
import fullPage from '@/components/full-page.vue';
|
|
|
|
|
|
|
2026-01-22 17:39:23 +08:00
|
|
|
|
const archiveId = ref('');
|
2026-01-26 15:39:14 +08:00
|
|
|
|
const loading = ref(false);
|
2026-05-27 16:22:22 +08:00
|
|
|
|
const keyword = ref('');
|
|
|
|
|
|
const activeViewType = ref('my');
|
|
|
|
|
|
const emptyText = ref('暂无回访计划');
|
2026-01-26 15:39:14 +08:00
|
|
|
|
const list = ref([]);
|
2026-05-27 16:22:22 +08:00
|
|
|
|
const categoryList = ref([
|
|
|
|
|
|
{ label: '我的回访', viewType: 'my' },
|
|
|
|
|
|
{ label: '团队回访', viewType: 'team' },
|
|
|
|
|
|
{ label: '柚助手', viewType: 'doctorMiniapp' },
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
let searchTimer = null;
|
2026-01-26 15:39:14 +08:00
|
|
|
|
|
|
|
|
|
|
const accountStore = useAccountStore();
|
|
|
|
|
|
const { account, doctorInfo } = storeToRefs(accountStore);
|
|
|
|
|
|
const { getDoctorInfo } = accountStore;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
onLoad(async (options) => {
|
2026-01-22 17:39:23 +08:00
|
|
|
|
archiveId.value = options?.archiveId ? String(options.archiveId) : '';
|
2026-05-27 16:22:22 +08:00
|
|
|
|
await ensureDoctor();
|
|
|
|
|
|
buildCategoryList();
|
2026-01-26 15:39:14 +08:00
|
|
|
|
loadList();
|
2026-01-22 17:39:23 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-26 15:39:14 +08:00
|
|
|
|
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 || '') || '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
function buildCategoryList() {
|
|
|
|
|
|
const d = doctorInfo.value || {};
|
|
|
|
|
|
const categories = [
|
|
|
|
|
|
{ label: '我的回访', viewType: 'my' },
|
|
|
|
|
|
{ label: '团队回访', viewType: 'team' },
|
|
|
|
|
|
];
|
|
|
|
|
|
if (d.hospitalId || d.hospitalName) {
|
|
|
|
|
|
categories.push({
|
|
|
|
|
|
label: String(d.hospitalName || '第一执业点'),
|
|
|
|
|
|
viewType: 'firstHospital',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
if (d.secondPracticeHospitalId || d.secondPracticeHospitalName) {
|
|
|
|
|
|
categories.push({
|
|
|
|
|
|
label: String(d.secondPracticeHospitalName || '第二执业点'),
|
|
|
|
|
|
viewType: 'secondHospital',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
categories.push({ label: '柚助手', viewType: 'doctorMiniapp' });
|
|
|
|
|
|
categoryList.value = categories;
|
|
|
|
|
|
if (!categories.some((item) => item.viewType === activeViewType.value)) {
|
|
|
|
|
|
activeViewType.value = categories[0]?.viewType || 'my';
|
|
|
|
|
|
}
|
2026-01-26 15:39:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function normalizePlan(raw) {
|
|
|
|
|
|
if (!raw || typeof raw !== 'object') return null;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
const id = String(raw._id || raw.planId || '');
|
2026-01-26 15:39:14 +08:00
|
|
|
|
if (!id) return null;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
const planId = String(raw.planId || raw._id || '');
|
2026-01-26 15:39:14 +08:00
|
|
|
|
const taskList = Array.isArray(raw.taskList) ? raw.taskList : [];
|
|
|
|
|
|
const first = taskList[0] && typeof taskList[0] === 'object' ? taskList[0] : {};
|
|
|
|
|
|
const eventType = String(first.eventType || '');
|
|
|
|
|
|
const taskContent = String(first.taskContent || '');
|
|
|
|
|
|
return {
|
|
|
|
|
|
...raw,
|
|
|
|
|
|
id,
|
2026-05-27 16:22:22 +08:00
|
|
|
|
_id: String(raw._id || id),
|
|
|
|
|
|
planId,
|
|
|
|
|
|
sourceTemplateId: String(raw.sourceTemplateId || raw._id || id),
|
|
|
|
|
|
sourceTemplatePlanId: String(raw.sourceTemplatePlanId || planId),
|
2026-01-26 15:39:14 +08:00
|
|
|
|
planName: String(raw.planName || ''),
|
|
|
|
|
|
planType: String(raw.planType || ''),
|
|
|
|
|
|
planDetail: String(raw.planDetail || ''),
|
|
|
|
|
|
firstEventType: eventType,
|
|
|
|
|
|
firstEventTypeLabel: eventType ? getTodoEventTypeLabel(eventType) : '',
|
|
|
|
|
|
taskContent,
|
|
|
|
|
|
taskCount: taskList.length,
|
|
|
|
|
|
taskList,
|
2026-05-27 16:22:22 +08:00
|
|
|
|
isFavorite: Boolean(raw.isFavorite),
|
2026-01-26 15:39:14 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
function unwrapLibraryData(res) {
|
|
|
|
|
|
const data = res?.data;
|
|
|
|
|
|
if (data && typeof data === 'object' && data.data && typeof data.data === 'object') {
|
|
|
|
|
|
return data.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
return data && typeof data === 'object' ? data : {};
|
2026-02-12 14:44:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-26 15:39:14 +08:00
|
|
|
|
async function loadList() {
|
|
|
|
|
|
if (loading.value) return;
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
|
try {
|
|
|
|
|
|
await ensureDoctor();
|
2026-05-27 16:22:22 +08:00
|
|
|
|
buildCategoryList();
|
2026-01-26 15:39:14 +08:00
|
|
|
|
const corpId = getCorpId();
|
|
|
|
|
|
const userId = getUserId();
|
2026-05-27 16:22:22 +08:00
|
|
|
|
if (!corpId || !userId) {
|
2026-01-26 15:39:14 +08:00
|
|
|
|
list.value = [];
|
2026-05-27 16:22:22 +08:00
|
|
|
|
toast('缺少用户信息');
|
2026-01-26 15:39:14 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-27 16:22:22 +08:00
|
|
|
|
const res = await api('getMyManagementPlanTemplateLibrary', {
|
2026-01-26 15:39:14 +08:00
|
|
|
|
corpId,
|
|
|
|
|
|
userId,
|
2026-05-27 16:22:22 +08:00
|
|
|
|
viewType: activeViewType.value,
|
|
|
|
|
|
keyword: keyword.value.trim(),
|
2026-01-26 15:39:14 +08:00
|
|
|
|
page: 1,
|
|
|
|
|
|
pageSize: 999,
|
|
|
|
|
|
});
|
|
|
|
|
|
if (!res?.success) {
|
|
|
|
|
|
list.value = [];
|
|
|
|
|
|
toast(res?.message || '获取回访计划失败');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-05-27 16:22:22 +08:00
|
|
|
|
const payload = unwrapLibraryData(res);
|
|
|
|
|
|
const arr = Array.isArray(payload.list) ? payload.list : [];
|
|
|
|
|
|
list.value = arr.map(normalizePlan).filter(Boolean);
|
|
|
|
|
|
emptyText.value = payload.emptyState || '暂无回访计划';
|
2026-01-26 15:39:14 +08:00
|
|
|
|
} finally {
|
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
function changeCategory(viewType) {
|
|
|
|
|
|
if (activeViewType.value === viewType) return;
|
|
|
|
|
|
activeViewType.value = viewType;
|
|
|
|
|
|
list.value = [];
|
|
|
|
|
|
loadList();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onSearchInput() {
|
|
|
|
|
|
if (searchTimer) clearTimeout(searchTimer);
|
|
|
|
|
|
searchTimer = setTimeout(() => {
|
|
|
|
|
|
loadList();
|
|
|
|
|
|
}, 400);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function canToggleFavorite(plan) {
|
|
|
|
|
|
if (!plan || !plan._id) return false;
|
2026-05-28 18:56:44 +08:00
|
|
|
|
if (isCreatedByCurrentUser(plan)) return false;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
if (activeViewType.value !== 'my') return true;
|
|
|
|
|
|
return Boolean(plan.isFavorite);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 18:56:44 +08:00
|
|
|
|
function isCreatedByCurrentUser(plan = {}) {
|
|
|
|
|
|
const userId = getUserId();
|
|
|
|
|
|
if (!userId) return false;
|
|
|
|
|
|
if (String(plan.createor || plan.creator || '') === userId) return true;
|
|
|
|
|
|
const signature = plan.creatorSignature && typeof plan.creatorSignature === 'object'
|
|
|
|
|
|
? plan.creatorSignature
|
|
|
|
|
|
: null;
|
|
|
|
|
|
return signature?.type === 'personal' && String(signature.person?.userId || '') === userId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
async function toggleFavorite(plan) {
|
|
|
|
|
|
const corpId = getCorpId();
|
|
|
|
|
|
const userId = getUserId();
|
|
|
|
|
|
const managementPlanId = String(plan?._id || '');
|
|
|
|
|
|
if (!corpId || !userId || !managementPlanId) return toast('缺少收藏信息');
|
|
|
|
|
|
const res = await api('toggleMyFollowupFavorite', {
|
|
|
|
|
|
corpId,
|
|
|
|
|
|
userId,
|
|
|
|
|
|
managementPlanId,
|
|
|
|
|
|
});
|
|
|
|
|
|
if (!res?.success) return toast(res?.message || '操作失败');
|
|
|
|
|
|
toast(res.message || '操作成功');
|
|
|
|
|
|
loadList();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getCreatorText(plan = {}) {
|
|
|
|
|
|
const signature = plan.creatorSignature && typeof plan.creatorSignature === 'object'
|
|
|
|
|
|
? plan.creatorSignature
|
|
|
|
|
|
: null;
|
|
|
|
|
|
if (signature?.type === 'institution') {
|
|
|
|
|
|
return signature.institution?.name || '';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (signature?.type === 'department') {
|
|
|
|
|
|
return signature.department?.name || '';
|
|
|
|
|
|
}
|
|
|
|
|
|
if (signature?.type === 'personal') {
|
|
|
|
|
|
return signature.person?.userName || '';
|
|
|
|
|
|
}
|
|
|
|
|
|
return String(plan.createorName || plan.creatorName || plan.teamName || plan.teanName || plan.createor || '');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function toService() {
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
|
url: '/pages/work/service/contact-service',
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-22 17:39:23 +08:00
|
|
|
|
function select(plan) {
|
|
|
|
|
|
uni.setStorageSync('select-mamagement-plan', plan);
|
2026-01-26 15:39:14 +08:00
|
|
|
|
uni.navigateTo({ url: `/pages/case/plan-execute?archiveId=${encodeURIComponent(archiveId.value)}` });
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function preview(plan) {
|
2026-01-26 15:39:14 +08:00
|
|
|
|
uni.setStorageSync('preview-mamagement-plan', plan);
|
|
|
|
|
|
uni.navigateTo({ url: `/pages/case/plan-preview?archiveId=${encodeURIComponent(archiveId.value)}` });
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.search-bar {
|
|
|
|
|
|
padding: 14rpx 18rpx 12rpx;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-bottom: 1rpx solid #edf0f2;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.search-input {
|
|
|
|
|
|
height: 68rpx;
|
|
|
|
|
|
padding: 0 24rpx;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
background: #f3f5f8;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
font-size: 28rpx;
|
2026-01-26 15:39:14 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.template-page {
|
|
|
|
|
|
height: 100%;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
display: flex;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
min-height: 0;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.category-panel {
|
|
|
|
|
|
width: 210rpx;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
background: #fbfcfe;
|
|
|
|
|
|
border-right: 1rpx solid #edf0f2;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.category-item {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
min-height: 88rpx;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
margin: 8rpx 10rpx;
|
|
|
|
|
|
padding: 14rpx 12rpx 14rpx 16rpx;
|
|
|
|
|
|
border-radius: 12rpx;
|
|
|
|
|
|
color: #374151;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
line-height: 40rpx;
|
|
|
|
|
|
box-sizing: border-box;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.category-item.active {
|
|
|
|
|
|
color: #1667e8;
|
|
|
|
|
|
background: #eef5ff;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
font-weight: 600;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.category-item.active::before {
|
|
|
|
|
|
content: "";
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
top: 18rpx;
|
|
|
|
|
|
bottom: 18rpx;
|
|
|
|
|
|
width: 6rpx;
|
|
|
|
|
|
border-radius: 999rpx;
|
|
|
|
|
|
background: #1667e8;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.category-text {
|
|
|
|
|
|
width: 100%;
|
2026-05-28 16:18:21 +08:00
|
|
|
|
display: block;
|
|
|
|
|
|
overflow: visible;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
word-break: break-all;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.content-panel {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
background: #f5f6f8;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.list-scroll {
|
|
|
|
|
|
height: 100%;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.state-text {
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.template-card {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
margin: 16rpx 16rpx 0;
|
|
|
|
|
|
padding: 26rpx 24rpx 24rpx;
|
|
|
|
|
|
border: 1rpx solid #eef1f4;
|
|
|
|
|
|
border-radius: 14rpx;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
background: #fff;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
box-shadow: 0 4rpx 14rpx rgba(17, 24, 39, 0.04);
|
|
|
|
|
|
box-sizing: border-box;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.card-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
gap: 16rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.plan-name {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
color: #111827;
|
|
|
|
|
|
font-size: 34rpx;
|
|
|
|
|
|
font-weight: 700;
|
|
|
|
|
|
line-height: 46rpx;
|
|
|
|
|
|
word-break: break-word;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.favorite-btn {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: flex-end;
|
|
|
|
|
|
margin-left: auto;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.favorite-icon {
|
|
|
|
|
|
font-size: 32rpx;
|
|
|
|
|
|
line-height: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.creator {
|
|
|
|
|
|
margin-top: 12rpx;
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
line-height: 40rpx;
|
2026-05-28 16:18:21 +08:00
|
|
|
|
word-break: break-all;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.task-link {
|
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
|
color: #1667e8;
|
|
|
|
|
|
font-size: 30rpx;
|
|
|
|
|
|
line-height: 40rpx;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.card-footer {
|
2026-01-22 17:39:23 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
2026-05-27 16:22:22 +08:00
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
gap: 18rpx;
|
|
|
|
|
|
margin-top: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.select-btn {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
min-width: 76rpx;
|
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
|
line-height: 46rpx;
|
|
|
|
|
|
padding: 0 18rpx;
|
|
|
|
|
|
border: 1rpx solid #1667e8;
|
|
|
|
|
|
border-radius: 999rpx;
|
|
|
|
|
|
color: #1667e8;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.footer {
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
box-shadow: 0 -6rpx 18rpx rgba(15, 23, 42, 0.06);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.service-entry {
|
|
|
|
|
|
padding: 24rpx 30rpx;
|
|
|
|
|
|
text-align: center;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.service-muted {
|
|
|
|
|
|
color: #6b7280;
|
|
|
|
|
|
font-size: 30rpx;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
2026-02-12 14:44:58 +08:00
|
|
|
|
|
2026-05-27 16:22:22 +08:00
|
|
|
|
.service-link {
|
|
|
|
|
|
color: #0877f1;
|
|
|
|
|
|
font-size: 30rpx;
|
2026-01-22 17:39:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
</style>
|