Commit 7b93c3f6794baad3393c7f20acc8ae6450ef3177

Authored by 王彪总
1 parent 3da5bb94

业务线 小程序不用写死,从后端接口获取

pages-sub/daily/maintain-manage/finish-plan-detail.vue
... ... @@ -14,6 +14,10 @@
14 14 <!-- 1. 计划名称:独立标题卡(设计稿顶部白卡) -->
15 15 <view class="record-head">
16 16 <view class="record-title">{{i.planName || '--'}}</view>
  17 + <!-- 按批次查看时一期次一条,用「第X次 + 上报状态」区分多次提交记录 -->
  18 + <view class="record-sub" v-if="i.sortNum">
  19 + 第 {{ i.sortNum }} 次 · {{ commitStateText(i.commitState) }}
  20 + </view>
17 21 </view>
18 22 <!-- 工单详情内容 -->
19 23 <view class="form-card">
... ... @@ -95,56 +99,66 @@
95 99 <view class="u-body-item-title">提交时间:</view>
96 100 <view class="u-line-1 u-body-value">{{ i.createTime==null?'--':timeFormat(i.createTime,'yyyy-mm-dd hh:MM:ss') }}</view>
97 101 </view>
  102 +
  103 + <!-- 本次养护被置为失效时,把原因一并展示 -->
  104 + <view class="u-body-item u-flex" v-if="i.commitState === 3">
  105 + <view class="u-body-item-title">失效原因:</view>
  106 + <view class="u-line-1 u-body-value">{{ i.invalidReason || '--' }}</view>
  107 + </view>
98 108 </view>
99 109  
100   - <!-- 动态配置的养护字段填报值(garden_work_record/garden_work_field_value),未填报过则整段不显示 -->
101   - <!-- 动态配置的养护字段填报值(garden_work_record/garden_work_field_value),未填报过则整段不显示 -->
102   -<view
103   - class="form-card"
104   - v-if="i.fieldRows && i.fieldRows.length"
105   ->
106   - <!-- 区块标题:蓝色竖条 + 标题 -->
107   - <view class="sec-head">
108   - <view class="sec-bar"></view>
109   - <view class="sec-title">养护填报内容</view>
110   - </view>
111   - <view class="u-body-item u-flex field-row" v-for="(f, fi) in i.fieldRows" :key="fi">
112   - <view class="u-body-item-title field-cell-title-multi">{{ f.name }}</view>
113   - <view class="field-value">
114   - <!-- 7 图片:复用本页照片的相册组件(预览/尺寸一致) -->
115   - <up-album
116   - v-if="f.kind === 'image'"
117   - :urls="f.images"
118   - singleSize="60"
119   - multipleSize="60"
120   - :preview-full-image="true"
121   - ></up-album>
122   - <!-- 6 多选 / 3 历史多选 / 9 关联记录:标签平铺(自绘,避免引入未使用的组件) -->
123   - <view v-else-if="f.kind === 'multi'" class="field-tags">
124   - <view v-for="(t, ti) in f.tags" :key="ti" class="field-tag">{{ t.text }}</view>
125   - </view>
126   - <!-- 8 附件:点击下载后用系统应用打开 -->
127   - <view v-else-if="f.kind === 'file'" class="field-tags">
128   - <text
129   - v-for="(file, ui) in f.files"
130   - :key="ui"
131   - class="field-file"
132   - @click="openFile(file)"
133   - >{{ file.name }}</text>
134   - </view>
135   - <!-- 10 链接:小程序不能直接打开外部 URL,点击复制 -->
136   - <text v-else-if="f.kind === 'link'" class="field-link" @click="copyLink(f.text)">{{ f.text }}</text>
137   - <!-- 11 地理位置:点击调微信原生地图(无需地图 AK) -->
138   - <text v-else-if="f.kind === 'geo' && f.geo" class="field-link" @click="openGeo(f.geo)">{{ f.text }}</text>
139   - <!-- 其余(1数值/2文本/3单选枚举/4日期/5布尔等)文本直出 -->
140   - <text v-else class="common-text-color field-text">{{ f.text }}</text>
141   - </view>
142   - </view>
143   -</view>
144   -<!-- 当没有填报字段,提示暂无提交记录 -->
145   -<view v-else class="no-record-tip">
146   - 直接结束了本次任务
147   -</view>
  110 + <!-- 动态配置的养护字段填报值:每条子上报(garden_work_record)单独一张卡,不把多次提交的数据混在一起 -->
  111 + <template v-if="i.recordRows && i.recordRows.length">
  112 + <view class="form-card" v-for="(r, ri) in i.recordRows" :key="ri">
  113 + <!-- 区块标题:蓝色竖条 + 标题;多条时右侧标注第几条与上报时间 -->
  114 + <view class="sec-head">
  115 + <view class="sec-bar"></view>
  116 + <view class="sec-title">养护填报内容</view>
  117 + <!-- 按批次查看时每个期次都标「第几条 + 上报时间」,单条记录也标,避免和上一期次的卡片混读 -->
  118 + <text class="sec-count" v-if="i.recordRows.length > 1 || i.sortNum">
  119 + 第 {{ ri + 1 }} 条 · {{ r.workTime == null ? '--' : timeFormat(r.workTime, 'yyyy-mm-dd hh:MM:ss') }}
  120 + </text>
  121 + </view>
  122 + <view class="u-body-item u-flex field-row" v-for="(f, fi) in r.fieldRows" :key="fi">
  123 + <view class="u-body-item-title field-cell-title-multi">{{ f.name }}</view>
  124 + <view class="field-value">
  125 + <!-- 7 图片:复用本页照片的相册组件(预览/尺寸一致) -->
  126 + <up-album
  127 + v-if="f.kind === 'image'"
  128 + :urls="f.images"
  129 + singleSize="60"
  130 + multipleSize="60"
  131 + :preview-full-image="true"
  132 + ></up-album>
  133 + <!-- 6 多选 / 3 历史多选 / 9 关联记录:标签平铺(自绘,避免引入未使用的组件) -->
  134 + <view v-else-if="f.kind === 'multi'" class="field-tags">
  135 + <view v-for="(t, ti) in f.tags" :key="ti" class="field-tag">{{ t.text }}</view>
  136 + </view>
  137 + <!-- 8 附件:点击下载后用系统应用打开 -->
  138 + <view v-else-if="f.kind === 'file'" class="field-tags">
  139 + <text
  140 + v-for="(file, ui) in f.files"
  141 + :key="ui"
  142 + class="field-file"
  143 + @click="openFile(file)"
  144 + >{{ file.name }}</text>
  145 + </view>
  146 + <!-- 10 链接:小程序不能直接打开外部 URL,点击复制 -->
  147 + <text v-else-if="f.kind === 'link'" class="field-link" @click="copyLink(f.text)">{{ f.text }}</text>
  148 + <!-- 11 地理位置:点击调微信原生地图(无需地图 AK) -->
  149 + <text v-else-if="f.kind === 'geo' && f.geo" class="field-link" @click="openGeo(f.geo)">{{ f.text }}</text>
  150 + <!-- 其余(1数值/2文本/3单选枚举/4日期/5布尔等)文本直出 -->
  151 + <text v-else class="common-text-color field-text">{{ f.text }}</text>
  152 + </view>
  153 + </view>
  154 + <!-- 该条上报没填字段时给个占位,避免出现一张空白卡 -->
  155 + <view class="no-field-tip" v-if="!r.fieldRows.length">本条未填写养护内容</view>
  156 + </view>
  157 + </template>
  158 + <!-- 当没有填报字段,提示暂无提交记录 -->
  159 + <view v-else class="no-record-tip">
  160 + {{ i.commitState === 3 ? '本次养护已置为失效,未填写养护内容' : '直接结束了本次任务' }}
  161 + </view>
148 162  
149 163 </view>
150 164 </template>
... ... @@ -195,18 +209,34 @@ const previewImage = (currentUrl, allUrls) =&gt; {
195 209 });
196 210 };
197 211  
  212 +/** 上报状态文案:1进行中/2已完成/3已失效 */
  213 +const commitStateText = (state) => {
  214 + if (state === 1) return '进行中'
  215 + if (state === 2) return '已完成'
  216 + if (state === 3) return '已失效'
  217 + return '--'
  218 +};
  219 +
198 220 /**
199 221 * 获取工单详情
  222 + * 传 batchNo 时返回该批次下所有期次的上报记录(一次一条期次,多次提交要全部列出);
  223 + * 只传 planNo 时仍按计划编码查单条,兼容原入口。
200 224 */
201   -const getOrderDetail = async (planNo: string, commitId?: string) => {
  225 +const getOrderDetail = async (planNo: string, commitId?: string, batchNo?: string) => {
202 226 console.log('getOrderDetail')
203 227 try {
204 228 loading.value = true;
205 229 let queryData: any = {
206   - planNo: planNo,
207 230 pageSize: commitId ? 1 : 100,
208 231 pageNo: 1,
209 232 };
  233 + // 计划编码 + 批次号同时带上:只查当前这一期次(planNo)的提交记录,批次号用于限定范围
  234 + if (planNo) {
  235 + queryData.planNo = planNo;
  236 + }
  237 + if (batchNo) {
  238 + queryData.batchNo = batchNo;
  239 + }
210 240 if (commitId) {
211 241 queryData.commitId = commitId;
212 242 }
... ... @@ -214,12 +244,25 @@ const getOrderDetail = async (planNo: string, commitId?: string) =&gt; {
214 244 console.log('接口返回:', res);
215 245 const list = res.data?.list || res.list || [];
216 246  
  247 + // 按批次查看时按「第几次」正序,读起来和 App 列表一致
  248 + if (batchNo) {
  249 + list.sort((a, b) => Number(a.sortNum || 0) - Number(b.sortNum || 0));
  250 + }
  251 +
217 252 orderDetail.value = list.map(item => {
218   - // ✅直接使用接口返回的 item.fields,不再读取 workRecords
  253 + // 一次养护可能有多次子上报(workRecords),每次上报有自己的字段值,逐条展示;
  254 + // 历史数据(双写上线前)没有 workRecords,退回用 item.fields 当唯一一条记录。
219 255 const useValues = Array.isArray(item.fields) ? item.fields : []
  256 + const workRecords = Array.isArray(item.workRecords) && item.workRecords.length
  257 + ? item.workRecords
  258 + : [{ workTime: item.createTime, values: useValues }]
220 259 return {
221 260 ...item,
222   - fieldRows: useValues.map(buildFieldRow)
  261 + // 每条子上报一行自己的字段渲染结果,模板里一条记录一张卡
  262 + recordRows: workRecords.map(record => ({
  263 + workTime: record?.workTime ?? item.createTime,
  264 + fieldRows: (Array.isArray(record?.values) ? record.values : []).map(buildFieldRow)
  265 + }))
223 266 }
224 267 })
225 268 } catch (error) {
... ... @@ -532,9 +575,9 @@ const openGeo = (geo) =&gt; {
532 575 // const workRecordIndex = ref(0)
533 576 // 页面加载
534 577 onLoad((options) => {
535   - const {planNo, commitId } = options;
536   - if (planNo) {
537   - getOrderDetail(planNo, commitId);
  578 + const {planNo, commitId, batchNo } = options;
  579 + if (planNo || batchNo) {
  580 + getOrderDetail(planNo, commitId, batchNo);
538 581 } else {
539 582 loading.value = false;
540 583 uni.showToast({title: '缺少工单ID', icon: 'none'});
... ... @@ -582,7 +625,9 @@ onLoad((options) =&gt; {
582 625 // 计划名称标题卡:白底 / 8px 圆角 / 卡片阴影 / 32rpx 500(设计稿顶部卡)
583 626 .record-head {
584 627 display: flex;
585   - align-items: center;
  628 + flex-direction: column;
  629 + align-items: flex-start;
  630 + gap: 8rpx;
586 631 margin: 0 24rpx 24rpx;
587 632 padding: 24rpx;
588 633 background: #ffffff;
... ... @@ -590,6 +635,13 @@ onLoad((options) =&gt; {
590 635 box-shadow: 0 4rpx 16rpx rgba(17, 24, 39, 0.06);
591 636 }
592 637  
  638 +// 标题卡副标题:第X次 + 上报状态
  639 +.record-sub {
  640 + font-size: 26rpx;
  641 + color: #6B7280;
  642 + line-height: 1.4;
  643 +}
  644 +
593 645 .record-title {
594 646 flex: 1;
595 647 min-width: 0;
... ... @@ -625,6 +677,21 @@ onLoad((options) =&gt; {
625 677 line-height: 1.4;
626 678 }
627 679  
  680 +/* 区块标题右侧:多条上报时标注第几条 + 上报时间 */
  681 +.sec-count {
  682 + margin-left: auto;
  683 + font-size: 24rpx;
  684 + color: #9CA3AF;
  685 + white-space: nowrap;
  686 +}
  687 +
  688 +/* 某条子上报没填字段时的占位文案 */
  689 +.no-field-tip {
  690 + font-size: 26rpx;
  691 + color: #9CA3AF;
  692 + padding: 8rpx 0;
  693 +}
  694 +
628 695 // 图片容器样式
629 696 .cell-content-wrap {
630 697 //padding: 10rpx 0;
... ...
pages-sub/daily/maintain-manage/index.vue
... ... @@ -91,9 +91,6 @@
91 91 <!-- </up-button>-->
92 92 <!-- </view>-->
93 93  
94   - <view class="common-custom-btn" style="--btn-top: 48px;" @click="goToDetail(item)">
95   - 养护任务
96   - </view>
97 94 <!-- <view class="u-body-item u-flex">-->
98 95 <!-- <view class="u-body-item-title">批次号:</view>-->
99 96 <!-- <view class="u-line-1 u-body-value">{{ item.batchNo || '-' }}</view>-->
... ...
pages-sub/daily/maintain-manage/type-list-page.vue
... ... @@ -14,14 +14,11 @@
14 14 <view class="task-card" v-for="(item, index) in currentList" :key="`${item.planNo}_${index}`">
15 15 <!-- 计划名称 -->
16 16 <view class="card-head">
17   - <view class="plan-name u-line-1">{{ item.planName || '无计划名称' }}</view>
18   - </view>
19   - <!-- 任务次数 -->
20   - <view class="info-row">
21   - <view class="info-label">任务次数</view>
22   - <view class="info-value" v-if="activeStatus === '2'">完成 {{ item.planFinishNum }} 次</view>
23   - <!-- 一次一条期次(planNum=1)时「第几次」取期次序号,历史多条次数的期次仍按完成次数递增 -->
24   - <view class="info-value" v-else>第 {{ item.planNum === 1 ? (item.sortNum || 1) : (item.planFinishNum + 1) }} 次</view>
  17 + <view class="plan-name-wrap">
  18 + <view class="plan-name u-line-1">{{ item.planName || '无计划名称' }}</view>
  19 + <!-- 同一批次下多个期次的计划名称相同,必须显示计划编码才能区分 -->
  20 + <view class="plan-no u-line-1" v-if="item.planNo">计划编码:{{ item.planNo }}</view>
  21 + </view>
25 22 </view>
26 23 <!-- 有效期 -->
27 24 <view class="info-row">
... ... @@ -31,6 +28,16 @@
31 28 timeFormat(item.endTime, 'yyyy-mm-dd') }}
32 29 </view>
33 30 </view>
  31 + <!-- 任务次数 -->
  32 + <view class="info-row">
  33 + <view class="info-label">任务次数</view>
  34 + <!-- 已完成:一次一条期次时每个期次只完成 1 次,必须带上期次序号才能区分多次提交记录 -->
  35 + <view class="info-value" v-if="activeStatus === '2'">
  36 + 有效期内第 {{ item.sortNum || 1 }} 个任务,共提交 {{ item.submitCount || 0 }} 次
  37 + </view>
  38 + <!-- 一次一条期次(planNum=1)时「第几次」取期次序号,历史多条次数的期次仍按完成次数递增 -->
  39 + <view class="info-value" v-else>第 {{ item.planNum === 1 ? (item.sortNum || 1) : (item.planFinishNum + 1) }} 次</view>
  40 + </view>
34 41 <!-- 操作区:统一收底,与信息区用分隔线隔开 -->
35 42 <view class="action-row">
36 43 <!-- 待完成且一次都没上报过才允许置为失效;已有养护记录(进行中/已完成过)不再显示 -->
... ... @@ -326,8 +333,11 @@ const handleGoWork = (item) =&gt; {
326 333 }
327 334 const handleGoWorkLook = (item) => {
328 335 const isView = activeStatus.value
  336 + // 已完成:一次一条期次,传批次号让详情页把该批次所有期次的上报记录一起列出来;
  337 + // 已失效:只看向被置为失效的那一次,仍按计划编码查单条。
  338 + const batchParam = activeStatus.value === '2' && item.batchNo ? `&batchNo=${item.batchNo}` : ''
329 339 uni.navigateTo({
330   - url: `/pages-sub/daily/maintain-manage/finish-plan-detail?planNo=${item.planNo}&planTypeId=${planTypeId.value}&businessType=${item.busiLine}&isView=${isView}`
  340 + url: `/pages-sub/daily/maintain-manage/finish-plan-detail?planNo=${item.planNo}&planTypeId=${planTypeId.value}&businessType=${item.busiLine}&isView=${isView}${batchParam}`
331 341 })
332 342 }
333 343 const handleEndTask = async (item) => {
... ... @@ -408,22 +418,31 @@ onUnload(() =&gt; {
408 418 display: flex;
409 419 align-items: center;
410 420 gap: 16rpx;
411   - margin-bottom: 16rpx;
  421 + /* 与 .plan-no / .info-row 的间距保持一致,卡内文字行上下距离统一 */
  422 + margin-bottom: 8rpx;
412 423 }
413   -.plan-name {
  424 +.plan-name-wrap {
414 425 flex: 1;
415 426 min-width: 0;
  427 +}
  428 +.plan-name {
416 429 font-size: 32rpx;
417 430 color: #1F2937;
418 431 font-weight: 500;
419 432 line-height: 1.4;
420 433 }
  434 +.plan-no {
  435 + margin-top: 8rpx;
  436 + font-size: 24rpx;
  437 + color: #9CA3AF;
  438 + line-height: 1.4;
  439 +}
421 440 .info-row {
422 441 display: flex;
423 442 align-items: center;
424 443 justify-content: space-between;
425 444 gap: 16rpx;
426   - margin-bottom: 6rpx;
  445 + margin-bottom: 8rpx;
427 446 }
428 447 .info-label {
429 448 font-size: 26rpx;
... ...
pages-sub/daily/maintain-manage/type-list.vue
1 1 <template>
2 2 <view class="type-grid">
3   - <!-- 动态渲染养护类型卡片 -->
4   - <template v-if="tagList.length > 0">
5   - <view class="type-card" v-for="(item, idx) in tagList" :key="idx" hover-class="type-card--hover"
  3 + <!-- 按养护类型渲染计划卡片:同一类型下多个批次合并成一张卡,批次号/计划名称等每项一行,多批次时逐行列出 -->
  4 + <template v-if="cardList.length > 0">
  5 + <view class="type-card" v-for="item in cardList" :key="item.key" hover-class="type-card--hover"
6 6 @click="toNextPage(item)">
7   - <!-- 类型图标:取类型名称首字,底色淡蓝 -->
8   - <view class="type-icon">{{ (item.planTypeName || '养护').charAt(0) }}</view>
9   - <view class="type-name">{{ item.planTypeName }}</view>
10   - <view class="type-foot">
11   - <text class="type-foot-label">待完成任务</text>
12   - <text class="type-count">{{ item.todayPendingCount }}</text>
  7 + <view class="info-row" v-for="row in item.rows" :key="row.label">
  8 + <text class="info-label">{{ row.label }}:</text>
  9 + <view class="info-value">
  10 + <view class="info-line" v-for="(value, idx) in row.values" :key="idx"
  11 + :class="{ 'info-line--count': row.label === '待完成任务' }">{{ value }}</view>
  12 + </view>
13 13 </view>
14 14 </view>
15 15 </template>
... ... @@ -20,15 +20,32 @@
20 20 </template>
21 21 <script setup lang="ts">
22 22 import { ref } from 'vue'
23   -import { onLoad, onShow, onUnload } from '@dcloudio/uni-app';
  23 +import { onShow, onUnload } from '@dcloudio/uni-app';
24 24  
25   -const tagList = ref<Array<{
  25 +const cardList = ref<Array<{
  26 + key: string
26 27 planTypeId: string | number
27   - planTypeName: string
28 28 batchNos: string[]
29   - todayPendingCount: number
  29 + rows: Array<{ label: string; values: string[] }>
30 30 }>>([])
31 31  
  32 +/** 日期字段可能是 'yyyy-MM-dd' 字符串(LocalDate)或时间戳,统一转成 yyyy-MM-dd */
  33 +const formatDate = (value: any) => {
  34 + if (value === null || value === undefined || value === '') return '--'
  35 + if (Array.isArray(value)) {
  36 + return `${value[0]}-${String(value[1]).padStart(2, '0')}-${String(value[2]).padStart(2, '0')}`
  37 + }
  38 + if (typeof value === 'number') {
  39 + const d = new Date(value)
  40 + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
  41 + }
  42 + // 'yyyy-MM-dd HH:mm:ss' 之类的字符串只取日期部分
  43 + return String(value).slice(0, 10)
  44 +}
  45 +
  46 +/** 去重并保持原顺序,合并卡片时避免同一个值重复占一行 */
  47 +const uniq = (list: any[]) => Array.from(new Set(list.filter(v => v !== null && v !== undefined && v !== '')))
  48 +
32 49 onShow(() => {
33 50 // 从storage拿上一页传过来完整对象
34 51 const item = uni.getStorageSync('temp_maintain_item')
... ... @@ -37,15 +54,43 @@ onShow(() =&gt; {
37 54 title: '数据异常,请返回重试',
38 55 icon: 'none'
39 56 });
40   - return;
  57 + return
41 58 }
42   - // 直接取planTypes
43   - tagList.value = item.planTypes || []
  59 + const roadName = item.roadName || '--'
  60 + // 接口已按养护类型分组,同一类型下的多个批次在这里合并成一张卡
  61 + cardList.value = (item.planTypes || []).map((type: any) => {
  62 + const batches = Array.isArray(type.batches) && type.batches.length
  63 + ? type.batches
  64 + : (type.batchNos || []).map((batchNo: string) => ({
  65 + batchNo,
  66 + planName: '',
  67 + beginTime: null,
  68 + endTime: null,
  69 + todayPendingCount: type.todayPendingCount
  70 + }))
  71 + const batchNos = batches.map((batch: any) => batch.batchNo).filter(Boolean)
  72 + const pendingCount = batches.reduce((sum: number, batch: any) => sum + Number(batch.todayPendingCount || 0), 0)
  73 + return {
  74 + key: String(type.planTypeId),
  75 + planTypeId: type.planTypeId,
  76 + batchNos,
  77 + rows: [
  78 + { label: '批次号', values: batchNos.length ? batchNos : ['--'] },
  79 + { label: '计划名称', values: uniq(batches.map((batch: any) => batch.planName)).length
  80 + ? uniq(batches.map((batch: any) => batch.planName)) : ['--'] },
  81 + { label: '道路名称', values: [roadName] },
  82 + { label: '计划类型', values: [type.planTypeName || '--'] },
  83 + { label: '执行时间', values: uniq(batches.map((batch: any) =>
  84 + `${formatDate(batch.beginTime)} - ${formatDate(batch.endTime)}`)) },
  85 + { label: '待完成任务', values: [`${pendingCount}次`] }
  86 + ]
  87 + }
  88 + })
44 89 });
45 90  
46   -// 标签点击跳转,batchNos存入storage,并且把planTypeId拼到url传给下一页
  91 +// 点击卡片跳到期次列表,把该类型下所有批次号一起带过去
47 92 const toNextPage = (item: any) => {
48   - uni.setStorageSync('temp_maintain_rawList', item.batchNos)
  93 + uni.setStorageSync('temp_maintain_rawList', item.batchNos || [])
49 94 uni.navigateTo({
50 95 url: `/pages-sub/daily/maintain-manage/type-list-page?planTypeId=${item.planTypeId}`
51 96 })
... ... @@ -57,15 +102,15 @@ onUnload(()=&gt;{
57 102 })
58 103 </script>
59 104 <style scoped lang="scss">
60   -/* 两列卡片栅格:页面 24rpx 内边距,卡片间距 16rpx(设计稿 .type-grid) */
  105 +/* 卡片列表:页面 24rpx 内边距,卡片间距 16rpx */
61 106 .type-grid {
62   - display: grid;
63   - grid-template-columns: 1fr 1fr;
  107 + display: flex;
  108 + flex-direction: column;
64 109 gap: 16rpx;
65 110 padding: 24rpx;
66 111 }
67 112  
68   -/* 卡片:12px 内边距 / 8px 圆角 / 8rpx 内部行距(设计稿 .type-card) */
  113 +/* 卡片:一张卡对应一个养护类型(多批次合并),撑满一行 */
69 114 .type-card {
70 115 display: flex;
71 116 flex-direction: column;
... ... @@ -82,69 +127,44 @@ onUnload(()=&gt;{
82 127 }
83 128 }
84 129  
85   -/* 类型图标位:68rpx 方块 + 淡蓝底(设计稿 .type-ico) */
86   -.type-icon {
87   - display: flex;
88   - align-items: center;
89   - justify-content: center;
90   - width: 68rpx;
91   - height: 68rpx;
92   - background: #EBF3FF;
93   - border-radius: 8rpx;
94   - font-size: 30rpx;
95   - font-weight: 600;
96   - color: #2563EB;
97   - line-height: 1;
98   -}
99   -
100   -/* 类型名称:14px / 500(设计稿 .type-card 标题) */
101   -.type-name {
102   - font-size: 28rpx;
103   - font-weight: 500;
104   - color: #1F2937;
105   - line-height: 1.4;
106   - white-space: nowrap;
107   - overflow: hidden;
108   - text-overflow: ellipsis;
109   -}
110   -
111   -/* 底部统计行:左侧说明 11px 浅灰,右侧数量标签(设计稿 .type-meta) */
112   -.type-foot {
  130 +/* 信息行:左侧字段名浅灰,右侧值右对齐;多个批次时值逐行显示 */
  131 +.info-row {
113 132 display: flex;
114   - align-items: center;
  133 + align-items: flex-start;
115 134 justify-content: space-between;
116   - margin-top: auto;
117   - font-size: 22rpx;
118   - color: #9CA3AF;
  135 + gap: 16rpx;
119 136 }
120 137  
121   -.type-foot-label {
122   - font-size: 22rpx;
  138 +.info-label {
  139 + flex-shrink: 0;
  140 + font-size: 26rpx;
123 141 color: #9CA3AF;
124 142 line-height: 1.5;
125 143 }
126 144  
127   -/* 数量标签:灰底胶囊(设计稿 .tag.gray) */
128   -.type-count {
129   - display: inline-flex;
130   - align-items: center;
131   - flex-shrink: 0;
132   - height: 40rpx;
133   - padding: 0 16rpx;
134   - background: #F4F6FA;
135   - border-radius: 8rpx;
136   - font-size: 22rpx;
137   - font-weight: 500;
  145 +.info-value {
  146 + flex: 1;
  147 + min-width: 0;
  148 + text-align: right;
  149 +}
  150 +
  151 +.info-line {
  152 + font-size: 26rpx;
138 153 color: #4B5563;
139   - line-height: 1;
  154 + line-height: 1.5;
  155 + word-break: break-all;
  156 +
  157 + /* 待完成次数加重,便于一眼看到 */
  158 + &--count {
  159 + color: #2563EB;
  160 + font-weight: 500;
  161 + }
140 162 }
141 163  
142   -/* 空状态 */
143 164 .type-empty {
144   - grid-column: 1 / -1;
145   - padding-top: 60rpx;
  165 + padding: 120rpx 0;
  166 + text-align: center;
146 167 font-size: 26rpx;
147 168 color: #9CA3AF;
148   - text-align: center;
149 169 }
150 170 </style>
... ...