提交
This commit is contained in:
1 parent
912ada02eb
commit
239d0a03d7
24 files changed
+935
-408
No files matched your search
@@ -160,6 +160,8 @@ export function fetchOutboundReleaseReviewList(params?: {
|
||||
keyword?: string
|
||||
/** pilot_service | clinical_application */
|
||||
bizType?: string
|
||||
infusionTimeStart?: string
|
||||
infusionTimeEnd?: string
|
||||
}) {
|
||||
return request.get<PageList<OutboundReleaseReview>>({
|
||||
url: '/web/admin/pilot-release-reviews',
|
||||
|
||||
@@ -185,31 +185,58 @@
|
||||
v-for="(att, attIdx) in row.attachments"
|
||||
:key="attIdx"
|
||||
class="paper-att-card"
|
||||
:class="{
|
||||
'paper-att-card--image': isImageFile(att),
|
||||
'paper-att-card--video': isVideoFile(att)
|
||||
}"
|
||||
:title="att.fileName"
|
||||
>
|
||||
<el-icon class="paper-att-card__icon"><Document /></el-icon>
|
||||
<span class="paper-att-card__name" :title="att.fileName">{{
|
||||
att.fileName || '附件'
|
||||
}}</span>
|
||||
<div
|
||||
class="paper-att-card__preview"
|
||||
:class="{
|
||||
'is-clickable': isImageFile(att) || isVideoFile(att)
|
||||
}"
|
||||
@click="
|
||||
(isImageFile(att) || isVideoFile(att)) && handlePreviewPaperAttachment(att)
|
||||
"
|
||||
>
|
||||
<img
|
||||
v-if="isImageFile(att)"
|
||||
:src="fullFileUrl(att.attachmentUrl)"
|
||||
:alt="att.fileName || '附件'"
|
||||
/>
|
||||
<template v-else-if="isVideoFile(att)">
|
||||
<div class="paper-att-card__type-icon paper-att-card__type-icon--video">
|
||||
<el-icon><VideoPlay /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-icon class="paper-att-card__type-icon paper-att-card__type-icon--doc">
|
||||
<Document />
|
||||
</el-icon>
|
||||
<span class="paper-att-card__name">{{ att.fileName || '附件' }}</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="paper-att-card__actions">
|
||||
<el-icon
|
||||
v-if="isImageFile(att)"
|
||||
v-if="isImageFile(att) || isVideoFile(att)"
|
||||
class="paper-att-card__action"
|
||||
title="预览"
|
||||
@click="handlePreviewPaperAttachment(att)"
|
||||
@click.stop="handlePreviewPaperAttachment(att)"
|
||||
>
|
||||
<View />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="paper-att-card__action"
|
||||
title="下载"
|
||||
@click="handleDownloadPaperAttachment(att)"
|
||||
@click.stop="handleDownloadPaperAttachment(att)"
|
||||
>
|
||||
<Download />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="paper-att-card__action paper-att-card__action--danger"
|
||||
title="删除"
|
||||
@click="removePaperAttachment($index, attIdx)"
|
||||
@click.stop="removePaperAttachment($index, attIdx)"
|
||||
>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
@@ -357,7 +384,8 @@
|
||||
Search,
|
||||
Document,
|
||||
Download,
|
||||
View
|
||||
View,
|
||||
VideoPlay
|
||||
} from '@element-plus/icons-vue'
|
||||
import { fetchUploadAttachment } from '@/api/business'
|
||||
import { fetchCellProductList } from '@/api/cell-product'
|
||||
@@ -874,6 +902,11 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
:deep(.el-upload) {
|
||||
display: block;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card {
|
||||
@@ -884,17 +917,62 @@
|
||||
background: #f8fafc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
padding: 6px 4px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.paper-att-card__icon {
|
||||
color: #0284c7;
|
||||
font-size: 18px;
|
||||
.paper-att-card__preview {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px 4px;
|
||||
overflow: hidden;
|
||||
|
||||
&.is-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card--image,
|
||||
.paper-att-card--video {
|
||||
.paper-att-card__preview {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card__type-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
&--doc {
|
||||
color: #0284c7;
|
||||
}
|
||||
|
||||
&--video {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
background: #ede9fe;
|
||||
color: #7c3aed;
|
||||
font-size: 20px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card__name {
|
||||
@@ -944,6 +1022,10 @@
|
||||
}
|
||||
|
||||
.paper-att-card--trigger {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
padding: 6px 4px;
|
||||
border: 1px dashed #a7f3d0;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
@@ -961,14 +1043,20 @@
|
||||
}
|
||||
|
||||
.paper-att-card__trigger-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #10b981;
|
||||
margin-bottom: 2px;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.paper-att-card--trigger span {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_storage_release_review_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/storage-release-review/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1"}, {"id": "qc_work_order_index_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L840"}, {"id": "qc_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1217"}, {"id": "qc_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1222"}, {"id": "qc_work_order_index_taskattachmentfullurl", "label": "taskAttachmentFullUrl()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1226"}, {"id": "qc_work_order_index_handletaskattachmentpreview", "label": "handleTaskAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1233"}, {"id": "qc_work_order_index_handletaskattachmentdownload", "label": "handleTaskAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1238"}, {"id": "qc_work_order_index_formatconfiguredlabitems", "label": "formatConfiguredLabItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1254"}, {"id": "qc_work_order_index_formatconfiguredthirditems", "label": "formatConfiguredThirdItems()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1260"}, {"id": "qc_work_order_index_buildtasktypesections", "label": "buildTaskTypeSections()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1271"}, {"id": "qc_work_order_index_buildconfiguredonlysection", "label": "buildConfiguredOnlySection()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1360"}, {"id": "qc_work_order_index_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1378"}, {"id": "qc_work_order_index_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1385"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_formattempcellproductfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L840", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1217", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_handlereceptionattachmentdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1222", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "qc_work_order_index_taskattachmentfullurl", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L1226", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_vieLine truncated
|
||||
@@ -10,21 +10,42 @@ import {
|
||||
qcStatusLabel,
|
||||
qcStatusTagType,
|
||||
scheduleStatusLabel,
|
||||
scheduleStatusTagType
|
||||
scheduleStatusTagType,
|
||||
sexLabel
|
||||
} from '@/utils/status-tag-registry'
|
||||
|
||||
/** 出库质检 + 中试服务:申请单 / 患者 / 输注方案 / 输注计划 / 产品明细 */
|
||||
export function buildOutboundPilotContextSections(detail: OutboundQcDetail): ViewSection[] {
|
||||
export type OutboundViewContextVariant = 'pilot_service' | 'clinical_application'
|
||||
|
||||
const SECTION_TITLES: Record<
|
||||
OutboundViewContextVariant,
|
||||
{ application: string; schedule: string }
|
||||
> = {
|
||||
pilot_service: {
|
||||
application: '中试服务申请单信息',
|
||||
schedule: '本次输注计划信息'
|
||||
},
|
||||
clinical_application: {
|
||||
application: '临床应用申请信息',
|
||||
schedule: '临床应用输注计划信息'
|
||||
}
|
||||
}
|
||||
|
||||
/** 出库工单/质检:申请单 / 患者 / 输注方案 / 输注计划 / 产品明细(码值转中文标签) */
|
||||
export function buildOutboundPilotContextSections(
|
||||
detail: OutboundQcDetail,
|
||||
variant: OutboundViewContextVariant = 'pilot_service'
|
||||
): ViewSection[] {
|
||||
const app = detail.application
|
||||
const patient = detail.patient
|
||||
const plan = detail.infusionPlan
|
||||
const schedule = detail.infusionSchedule
|
||||
const products = detail.products || []
|
||||
const titles = SECTION_TITLES[variant]
|
||||
const result: ViewSection[] = []
|
||||
|
||||
if (app) {
|
||||
result.push({
|
||||
title: '中试服务申请单信息',
|
||||
title: titles.application,
|
||||
fields: [
|
||||
{ label: '申请单号', value: app.applicationNo || '—' },
|
||||
{ label: '申请单名称', value: app.applicationName || '—' },
|
||||
@@ -43,7 +64,7 @@ export function buildOutboundPilotContextSections(detail: OutboundQcDetail): Vie
|
||||
title: '患者信息',
|
||||
fields: [
|
||||
{ label: '患者姓名', value: patient.patientName || '—' },
|
||||
{ label: '性别', value: patient.sex || '—' },
|
||||
{ label: '性别', value: sexLabel(String(patient.sex ?? '')) || '—' },
|
||||
{ label: '年龄', value: patient.age || '—' },
|
||||
{ label: '联系电话', value: patient.phoneNo || '—' },
|
||||
{
|
||||
@@ -98,7 +119,7 @@ export function buildOutboundPilotContextSections(detail: OutboundQcDetail): Vie
|
||||
if (schedule.cancelReason) {
|
||||
scheduleFields.push({ label: '取消原因', value: schedule.cancelReason, span: true })
|
||||
}
|
||||
result.push({ title: '本次输注计划信息', fields: scheduleFields })
|
||||
result.push({ title: titles.schedule, fields: scheduleFields })
|
||||
}
|
||||
|
||||
if (products.length) {
|
||||
|
||||
+103
-15
@@ -212,31 +212,58 @@
|
||||
v-for="(att, attIdx) in row.attachments"
|
||||
:key="attIdx"
|
||||
class="paper-att-card"
|
||||
:class="{
|
||||
'paper-att-card--image': isImageFile(att),
|
||||
'paper-att-card--video': isVideoFile(att)
|
||||
}"
|
||||
:title="att.fileName"
|
||||
>
|
||||
<el-icon class="paper-att-card__icon"><Document /></el-icon>
|
||||
<span class="paper-att-card__name" :title="att.fileName">{{
|
||||
att.fileName || '附件'
|
||||
}}</span>
|
||||
<div
|
||||
class="paper-att-card__preview"
|
||||
:class="{
|
||||
'is-clickable': isImageFile(att) || isVideoFile(att)
|
||||
}"
|
||||
@click="
|
||||
(isImageFile(att) || isVideoFile(att)) && handlePreviewPaperAttachment(att)
|
||||
"
|
||||
>
|
||||
<img
|
||||
v-if="isImageFile(att)"
|
||||
:src="fullFileUrl(att.attachmentUrl)"
|
||||
:alt="att.fileName || '附件'"
|
||||
/>
|
||||
<template v-else-if="isVideoFile(att)">
|
||||
<div class="paper-att-card__type-icon paper-att-card__type-icon--video">
|
||||
<el-icon><VideoPlay /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<el-icon class="paper-att-card__type-icon paper-att-card__type-icon--doc">
|
||||
<Document />
|
||||
</el-icon>
|
||||
<span class="paper-att-card__name">{{ att.fileName || '附件' }}</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="paper-att-card__actions">
|
||||
<el-icon
|
||||
v-if="isImageFile(att)"
|
||||
v-if="isImageFile(att) || isVideoFile(att)"
|
||||
class="paper-att-card__action"
|
||||
title="预览"
|
||||
@click="handlePreviewPaperAttachment(att)"
|
||||
@click.stop="handlePreviewPaperAttachment(att)"
|
||||
>
|
||||
<View />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="paper-att-card__action"
|
||||
title="下载"
|
||||
@click="handleDownloadPaperAttachment(att)"
|
||||
@click.stop="handleDownloadPaperAttachment(att)"
|
||||
>
|
||||
<Download />
|
||||
</el-icon>
|
||||
<el-icon
|
||||
class="paper-att-card__action paper-att-card__action--danger"
|
||||
title="删除"
|
||||
@click="removePaperAttachment($index, attIdx)"
|
||||
@click.stop="removePaperAttachment($index, attIdx)"
|
||||
>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
@@ -398,7 +425,8 @@
|
||||
Search,
|
||||
Document,
|
||||
Download,
|
||||
View
|
||||
View,
|
||||
VideoPlay
|
||||
} from '@element-plus/icons-vue'
|
||||
import { fetchUploadAttachment } from '@/api/business'
|
||||
import { fetchCellProductList } from '@/api/cell-product'
|
||||
@@ -908,6 +936,11 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
|
||||
:deep(.el-upload) {
|
||||
display: block;
|
||||
line-height: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card {
|
||||
@@ -918,17 +951,62 @@
|
||||
background: #f8fafc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
padding: 6px 4px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.paper-att-card__icon {
|
||||
color: #0284c7;
|
||||
font-size: 18px;
|
||||
.paper-att-card__preview {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 6px 4px;
|
||||
overflow: hidden;
|
||||
|
||||
&.is-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card--image,
|
||||
.paper-att-card--video {
|
||||
.paper-att-card__preview {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card__type-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 22px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
&--doc {
|
||||
color: #0284c7;
|
||||
}
|
||||
|
||||
&--video {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 8px;
|
||||
background: #ede9fe;
|
||||
color: #7c3aed;
|
||||
font-size: 20px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.paper-att-card__name {
|
||||
@@ -978,6 +1056,10 @@
|
||||
}
|
||||
|
||||
.paper-att-card--trigger {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
padding: 6px 4px;
|
||||
border: 1px dashed #a7f3d0;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
@@ -995,14 +1077,20 @@
|
||||
}
|
||||
|
||||
.paper-att-card__trigger-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #10b981;
|
||||
margin-bottom: 2px;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.paper-att-card--trigger span {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
|
||||
@@ -33,9 +33,22 @@
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="输注时间">
|
||||
<el-date-picker
|
||||
v-model="searchForm.infusionTimeRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="filter-actions-row">
|
||||
<span class="filter-hint">支持按申请单号、患者姓名搜索。</span>
|
||||
<span class="filter-hint"
|
||||
>支持按申请单号、患者姓名搜索;输注时间默认今天前 15 天至后 15 天。</span
|
||||
>
|
||||
<div class="filter-actions-end">
|
||||
<el-button class="btn-ghost" @click="handleReset">
|
||||
<el-icon><RefreshLeft /></el-icon>重置
|
||||
@@ -267,9 +280,27 @@
|
||||
{ value: 'btg', label: '不通过' }
|
||||
]
|
||||
|
||||
function formatLocalDate(d: Date) {
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
return `${y}-${m}-${day}`
|
||||
}
|
||||
|
||||
/** 输注时间默认:今天前 15 天 ~ 今天后 15 天 */
|
||||
function getDefaultInfusionTimeRange(): [string, string] {
|
||||
const today = new Date()
|
||||
const start = new Date(today)
|
||||
start.setDate(start.getDate() - 15)
|
||||
const end = new Date(today)
|
||||
end.setDate(end.getDate() + 15)
|
||||
return [formatLocalDate(start), formatLocalDate(end)]
|
||||
}
|
||||
|
||||
const searchForm = reactive({
|
||||
reviewConclusion: '',
|
||||
keyword: ''
|
||||
keyword: '',
|
||||
infusionTimeRange: getDefaultInfusionTimeRange() as [string, string]
|
||||
})
|
||||
const tableData = ref<OutboundReleaseReview[]>([])
|
||||
const selectedRows = ref<OutboundReleaseReview[]>([])
|
||||
@@ -290,7 +321,9 @@
|
||||
pageSize: pagination.pageSize,
|
||||
reviewConclusion: searchForm.reviewConclusion || undefined,
|
||||
keyword: searchForm.keyword || undefined,
|
||||
bizType: effectiveBizType.value
|
||||
bizType: effectiveBizType.value,
|
||||
infusionTimeStart: searchForm.infusionTimeRange?.[0] || undefined,
|
||||
infusionTimeEnd: searchForm.infusionTimeRange?.[1] || undefined
|
||||
})
|
||||
tableData.value = res.list || []
|
||||
pagination.total = res.total ?? 0
|
||||
@@ -307,6 +340,7 @@
|
||||
function handleReset() {
|
||||
searchForm.reviewConclusion = ''
|
||||
searchForm.keyword = ''
|
||||
searchForm.infusionTimeRange = getDefaultInfusionTimeRange()
|
||||
pagination.page = 1
|
||||
loadData()
|
||||
}
|
||||
|
||||
@@ -199,10 +199,10 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
{{
|
||||
row.amount
|
||||
row.amount != null && row.amount !== ''
|
||||
? '¥' +
|
||||
Number(row.amount).toLocaleString('zh-CN', { minimumFractionDigits: 2 })
|
||||
: '-'
|
||||
: '—'
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -215,13 +215,13 @@
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-if="row.paymentStatus"
|
||||
:type="payStatusTagType(row.paymentStatus)"
|
||||
v-if="row.payStatus"
|
||||
:type="payStatusTagType(row.payStatus)"
|
||||
size="small"
|
||||
>
|
||||
{{ payStatusLabel(row.paymentStatus) }}
|
||||
{{ payStatusLabel(row.payStatus) }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@@ -552,10 +552,21 @@
|
||||
}
|
||||
|
||||
const buildCompleteConfirmMessage = (row: any) => {
|
||||
const orderTypeLabel = channelServiceOrderTypeLabel(row.orderType)
|
||||
const patient = row.patientName ? `患者「${row.patientName}」` : '该患者'
|
||||
const pendingConfirmHint =
|
||||
getInfusionStatus(row) === 'dtz' ? '当前为待输注,系统将先记录用户确认再标记完成。' : ''
|
||||
|
||||
if (isClinical.value) {
|
||||
const paymentHint =
|
||||
'临床应用不在此扣减渠道服务订单费用,缴费请在「缴费信息」中单独处理。'
|
||||
return `${patient}的输注计划将标记为已完成。${pendingConfirmHint}${paymentHint}是否继续?`
|
||||
}
|
||||
|
||||
const orderTypeLabel = channelServiceOrderTypeLabel(row.orderType)
|
||||
const statusHint =
|
||||
getInfusionStatus(row) === 'dtz' ? '当前为待输注,系统将先记录用户确认再完成结算。' : ''
|
||||
getInfusionStatus(row) === 'dtz'
|
||||
? '当前为待输注,系统将先记录用户确认再完成结算。'
|
||||
: ''
|
||||
let settlementHint = '并触发关联服务订单的结算扣减。'
|
||||
if (row.orderType === 'yfk') {
|
||||
settlementHint = `关联服务订单类型为「${orderTypeLabel}」,系统将按渠道协议单价扣减服务订单账户余额。`
|
||||
@@ -603,7 +614,9 @@
|
||||
scheduleId,
|
||||
infusionStatus: 'ywc'
|
||||
})
|
||||
ElMessage.success('输注计划已完成,结算扣减已处理')
|
||||
ElMessage.success(
|
||||
isClinical.value ? '输注计划已完成' : '输注计划已完成,结算扣减已处理'
|
||||
)
|
||||
loadData()
|
||||
} catch (e: any) {
|
||||
if (e !== 'cancel') {
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
</el-tag>
|
||||
<el-button
|
||||
v-if="editor.selectedStep.value.stepStatus === 'dzx'"
|
||||
class="btn-op-item primary"
|
||||
size="small"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
:loading="editor.stepActionLoading.value"
|
||||
:disabled="editor.manualSaveLoading.value"
|
||||
@click="editor.handleStartStep(editor.selectedStep.value)"
|
||||
@@ -35,9 +35,8 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button
|
||||
class="btn-main"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="editor.manualSaveLoading.value"
|
||||
:disabled="editor.stepActionLoading.value"
|
||||
@click="editor.handleManualSave"
|
||||
|
||||
@@ -40,9 +40,8 @@
|
||||
<div v-if="!readonly" class="execution-header-actions">
|
||||
<el-button
|
||||
v-if="editor.taskDetail.value.taskStatus === 'dpz'"
|
||||
class="btn-main"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="editor.taskActionLoading.value"
|
||||
@click="editor.handleStartTask"
|
||||
>
|
||||
@@ -53,9 +52,8 @@
|
||||
editor.taskDetail.value.taskStatus === 'jxz' ||
|
||||
editor.taskDetail.value.taskStatus === 'ywc'
|
||||
"
|
||||
class="btn-main"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="success"
|
||||
size="small"
|
||||
:loading="editor.taskActionLoading.value"
|
||||
@click="editor.handleCompleteTask"
|
||||
>
|
||||
@@ -263,13 +261,13 @@
|
||||
<h3>📥 原材料(样本/细胞产品)<span class="virtual-step-required">必填</span></h3>
|
||||
<div v-if="!readonly" class="execution-detail-actions">
|
||||
<el-button
|
||||
class="btn-main"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="editor.inputSaving.value"
|
||||
@click="editor.saveTaskInputs"
|
||||
><el-icon><Check /></el-icon>保存</el-button
|
||||
>
|
||||
<el-icon><Check /></el-icon>保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="execution-detail-body">
|
||||
@@ -293,13 +291,13 @@
|
||||
<h3>📤 产出(细胞产品)</h3>
|
||||
<div v-if="!readonly" class="execution-detail-actions">
|
||||
<el-button
|
||||
class="btn-main"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
size="small"
|
||||
:loading="editor.outputSaving.value"
|
||||
@click="editor.saveTaskOutputs"
|
||||
><el-icon><Check /></el-icon>保存</el-button
|
||||
>
|
||||
<el-icon><Check /></el-icon>保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="execution-detail-body">
|
||||
@@ -712,3 +710,26 @@
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 弹窗 teleport 到 body,工具栏按钮样式需挂 execution-dialog 全局类 -->
|
||||
<style lang="scss">
|
||||
.execution-dialog {
|
||||
.task-exec-toolbar-btn.el-button {
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
padding: 0 14px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
|
||||
> span {
|
||||
font-size: 14px;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.el-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -4,11 +4,11 @@
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">原材料(样本/细胞产品)</h2>
|
||||
<div v-if="!disabled" class="panel-top-actions">
|
||||
<el-button type="primary" size="small" @click="handleAddSample">
|
||||
<el-button class="btn-main task-exec-toolbar-btn" type="primary" @click="handleAddSample">
|
||||
<el-icon><Plus /></el-icon>
|
||||
添加样本
|
||||
</el-button>
|
||||
<el-button size="small" @click="handleAddCellProduct">
|
||||
<el-button class="btn-ghost task-exec-toolbar-btn" @click="handleAddCellProduct">
|
||||
<el-icon><Plus /></el-icon>
|
||||
添加细胞产品
|
||||
</el-button>
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
<!-- 工具栏 -->
|
||||
<div class="panel-top">
|
||||
<h2 class="title-bar-heading">产出(细胞产品)</h2>
|
||||
<el-button v-if="!disabled" type="primary" size="small" @click="handleAdd">
|
||||
<el-button
|
||||
v-if="!disabled"
|
||||
class="btn-main task-exec-toolbar-btn"
|
||||
type="primary"
|
||||
@click="handleAdd"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
新增产出
|
||||
</el-button>
|
||||
|
||||
@@ -1,72 +1,46 @@
|
||||
<!-- 生产工单展开行 · 生产任务子列表 -->
|
||||
<template>
|
||||
<div class="work-order-task-sublist">
|
||||
<div class="list-toolbar work-order-task-sublist__toolbar">
|
||||
<div class="list-toolbar-row">
|
||||
<el-button
|
||||
class="btn-main"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
<div class="work-order-task-sublist__panel" v-loading="loading">
|
||||
<div v-if="tableData.length" class="work-order-task-cards-wrap">
|
||||
<div class="work-order-task-sublist__summary">
|
||||
<span class="work-order-task-sublist__count">共 {{ tableData.length }} 项任务</span>
|
||||
<el-button
|
||||
class="work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main work-order-task-sublist__dispatch"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
</div>
|
||||
<div
|
||||
v-for="(row, idx) in tableData"
|
||||
:key="row.id || idx"
|
||||
class="work-order-task-card"
|
||||
@dblclick="handleViewDetail(row)"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
<el-button class="btn-ghost" size="small" :loading="loading" @click="loadData">
|
||||
<el-icon><RefreshLeft /></el-icon>刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="work-order-task-sublist__body">
|
||||
<el-table
|
||||
class="list-table work-order-task-sublist__table"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
size="small"
|
||||
@row-dblclick="handleViewDetail"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
:index="(i) => i + 1"
|
||||
/>
|
||||
<el-table-column prop="taskNo" label="任务号" min-width="150" align="center" />
|
||||
<el-table-column prop="taskType" label="任务类型" min-width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="work-order-task-card__head">
|
||||
<span class="work-order-task-card__name">{{ row.taskName || row.taskNo || '—' }}</span>
|
||||
<el-tag :type="taskStatusTag(row.taskStatus).type" size="small">
|
||||
{{ taskStatusTag(row.taskStatus).label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="work-order-task-card__meta">
|
||||
<span class="work-order-task-card__code">{{ row.taskNo || '—' }}</span>
|
||||
<el-tag :type="productionTaskTypeTag(row.taskType, row.orderSource).type" size="small">
|
||||
{{ productionTaskTypeTag(row.taskType, row.orderSource).label }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="taskName"
|
||||
label="任务名称"
|
||||
min-width="160"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
<el-table-column
|
||||
prop="routeName"
|
||||
label="工艺路线"
|
||||
min-width="140"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
>
|
||||
<template #default="{ row }">{{ row.routeName || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="taskStatus" label="任务状态" min-width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="taskStatusTag(row.taskStatus).type" size="small">{{
|
||||
taskStatusTag(row.taskStatus).label
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="conclusion" label="生产结论" min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
v-if="productionConclusionTagType(row.conclusion)"
|
||||
:type="productionConclusionTagType(row.conclusion)"
|
||||
@@ -74,63 +48,81 @@
|
||||
>
|
||||
{{ row.conclusionLabel || productionConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="startedTime" label="开始时间" min-width="170" align="center">
|
||||
<template #default="{ row }">{{ row.startedTime || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="completedTime" label="完成时间" min-width="170" align="center">
|
||||
<template #default="{ row }">{{ row.completedTime || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="260" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="work-order-task-sublist__ops">
|
||||
<el-button
|
||||
v-if="canEnterExecution(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="handleEnterExecution(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>进入执行
|
||||
</div>
|
||||
<div class="work-order-task-sublist__ops">
|
||||
<el-button
|
||||
v-if="canEnterExecution(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleEnterExecution(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>进入执行
|
||||
</el-button>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleViewDetail(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<el-button v-else class="btn-op-item primary" @click="handleViewDetail(row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item">
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canEnterExecution(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editInfo">
|
||||
<el-icon><EditPen /></el-icon>编辑信息
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editRoute">
|
||||
<el-icon><EditPen /></el-icon>编辑工艺
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty
|
||||
v-if="!loading && !tableData.length"
|
||||
description="暂无任务,可点击「派发任务」创建"
|
||||
:image-size="72"
|
||||
/>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="canEnterExecution(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editInfo">
|
||||
<el-icon><EditPen /></el-icon>编辑信息
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canEditTask(row)" command="editRoute">
|
||||
<el-icon><EditPen /></el-icon>编辑工艺
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!loading" class="work-order-task-cards-wrap work-order-task-cards-wrap--empty">
|
||||
<div class="work-order-task-sublist__summary">
|
||||
<el-button
|
||||
class="work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
<el-button
|
||||
class="btn-main work-order-task-sublist__dispatch"
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!canDispatch"
|
||||
@click="handleDispatch"
|
||||
>
|
||||
<el-icon><Position /></el-icon>派发任务
|
||||
</el-button>
|
||||
</div>
|
||||
<el-empty
|
||||
class="work-order-task-sublist__empty"
|
||||
description="暂无任务,可点击「派发任务」创建"
|
||||
:image-size="56"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TaskExecutionDialog
|
||||
@@ -325,36 +317,139 @@
|
||||
|
||||
<style scoped lang="scss">
|
||||
.work-order-task-sublist {
|
||||
padding: 12px 16px 16px 40px;
|
||||
padding: 8px 12px 10px 40px;
|
||||
background: #f8fafc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__toolbar {
|
||||
padding: 0 0 8px;
|
||||
border-bottom: none;
|
||||
.work-order-task-sublist__panel {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__body {
|
||||
display: block;
|
||||
width: 100%;
|
||||
.work-order-task-cards-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__summary {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 8px;
|
||||
padding-top: 8px;
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__count {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
line-height: 1.35;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__refresh-icon {
|
||||
flex-shrink: 0;
|
||||
padding: 0 2px;
|
||||
height: 20px;
|
||||
font-size: 14px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-sublist__dispatch {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.work-order-task-cards-wrap--empty {
|
||||
align-items: center;
|
||||
|
||||
.work-order-task-sublist__summary {
|
||||
padding-top: 0;
|
||||
min-height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-sublist__empty {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
padding: 4px 0;
|
||||
|
||||
:deep(.el-empty__description) {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 0 0 248px;
|
||||
width: 248px;
|
||||
max-width: 248px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
cursor: default;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 6px rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-task-card__head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.work-order-task-card__name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
line-height: 1.35;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.work-order-task-card__meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.work-order-task-card__code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
line-height: 1.35;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__table {
|
||||
width: 100%;
|
||||
|
||||
:deep(.el-table__inner-wrapper),
|
||||
:deep(.el-table__header-wrapper),
|
||||
:deep(.el-table__body-wrapper) {
|
||||
width: 100%;
|
||||
}
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.work-order-task-sublist__ops {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
</style>
|
||||
@@ -141,9 +141,14 @@
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.bizType === 'pilot_service' ? 'primary' : 'success'" size="small">
|
||||
{{ row.bizTypeLabel || '—' }}
|
||||
<el-tag
|
||||
v-if="row.bizType"
|
||||
:type="bizTypeTagType(row.bizType) as TagType"
|
||||
size="small"
|
||||
>
|
||||
{{ row.bizTypeLabel || bizTypeLabel(row.bizType) }}
|
||||
</el-tag>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@@ -546,7 +551,9 @@
|
||||
donationStatusLabel,
|
||||
donationStatusTagType,
|
||||
productStatusLabel,
|
||||
productStatusTagType
|
||||
productStatusTagType,
|
||||
bizTypeLabel,
|
||||
bizTypeTagType
|
||||
} from '@/utils/status-tag-registry'
|
||||
import { buildOutboundPilotContextSections } from '@/utils/outbound-qc-pilot-view-sections'
|
||||
import type { OutboundQcDetail } from '@/api/qc-work-order'
|
||||
@@ -873,15 +880,17 @@
|
||||
|
||||
const viewVisible = ref(false)
|
||||
const detail = ref<ProductionWorkOrderDetail | null>(null)
|
||||
const isOutboundPilotService = computed(
|
||||
const isOutboundContextView = computed(
|
||||
() =>
|
||||
detail.value?.workOrderType === 'outbound' && detail.value?.bizType === 'pilot_service'
|
||||
detail.value?.workOrderType === 'outbound' &&
|
||||
(detail.value?.bizType === 'pilot_service' ||
|
||||
detail.value?.bizType === 'clinical_application')
|
||||
)
|
||||
const viewDialogWidth = computed(() => (isOutboundPilotService.value ? '1200px' : '720px'))
|
||||
const viewDialogWidth = computed(() => (isOutboundContextView.value ? '1200px' : '720px'))
|
||||
const viewDialogGridColumns = computed<2 | 3 | 4>(() =>
|
||||
isOutboundPilotService.value ? 4 : 2
|
||||
isOutboundContextView.value ? 4 : 2
|
||||
)
|
||||
const viewDialogCompact = computed(() => isOutboundPilotService.value)
|
||||
const viewDialogCompact = computed(() => isOutboundContextView.value)
|
||||
const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '').replace(/\/$/, '')
|
||||
|
||||
const viewReceptionAttachmentFiles = computed(() => {
|
||||
@@ -959,14 +968,8 @@
|
||||
if (isOutbound) {
|
||||
baseFields.push({
|
||||
label: '业务类型',
|
||||
value:
|
||||
d.bizTypeLabel ||
|
||||
(d.bizType === 'pilot_service'
|
||||
? '中试服务'
|
||||
: d.bizType === 'clinical_application'
|
||||
? '临床应用'
|
||||
: '—'),
|
||||
tagType: 'primary' as const
|
||||
value: d.bizTypeLabel || bizTypeLabel(d.bizType || '') || '—',
|
||||
tagType: bizTypeTagType(d.bizType || '') as TagType
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1010,62 +1013,19 @@
|
||||
|
||||
const sections: ViewSection[] = [{ title: '基本信息', fields: baseFields }]
|
||||
|
||||
// outbound: 中试服务 — 与出库质检工单查看弹窗一致;临床应用 — 保留简要申请/输注信息
|
||||
if (isOutbound) {
|
||||
if (d.bizType === 'pilot_service') {
|
||||
const pilotDetail: OutboundQcDetail = {
|
||||
workOrder: {} as OutboundQcDetail['workOrder'],
|
||||
application: d.application,
|
||||
patient: d.patient,
|
||||
infusionPlan: d.infusionPlan,
|
||||
infusionSchedule: d.infusionSchedule,
|
||||
products: d.products
|
||||
}
|
||||
sections.push(...buildOutboundPilotContextSections(pilotDetail))
|
||||
} else {
|
||||
const pa = d.pilotApplication || {}
|
||||
const sched = d.infusionSchedule || {}
|
||||
const appStatusLabel = (s: string) => {
|
||||
const m: Record<string, string> = {
|
||||
dks: '待开始',
|
||||
jxz: '进行中',
|
||||
ywc: '已完成',
|
||||
yzf: '已作废'
|
||||
}
|
||||
return m[s] || s || '—'
|
||||
}
|
||||
const appStatusTagType = (s: string) => {
|
||||
const m: Record<string, string> = {
|
||||
dks: 'info',
|
||||
jxz: 'warning',
|
||||
ywc: 'success',
|
||||
yzf: 'danger'
|
||||
}
|
||||
return m[s] || 'info'
|
||||
}
|
||||
sections.push({
|
||||
title: '中试申请信息',
|
||||
fields: [
|
||||
{ label: '申请单号', value: pa.applicationNo || '—' },
|
||||
{ label: '申请名称', value: pa.applicationName || '—' },
|
||||
{
|
||||
label: '申请状态',
|
||||
value: appStatusLabel(pa.applicationStatus || ''),
|
||||
tagType: appStatusTagType(pa.applicationStatus || '') as any
|
||||
}
|
||||
]
|
||||
})
|
||||
sections.push({
|
||||
title: '输注计划信息',
|
||||
fields: [
|
||||
{ label: '细胞类型', value: sched.cellType || '—' },
|
||||
{ label: '规格', value: sched.specText || '—' },
|
||||
{ label: '输注时间', value: sched.infusionTime || '—' },
|
||||
{ label: '输注地点', value: sched.infusionLocation || '—' },
|
||||
{ label: '输注方式', value: sched.infusionMethod || '—' }
|
||||
]
|
||||
})
|
||||
// outbound:中试服务 / 临床应用 — 与出库质检一致,码值展示中文标签
|
||||
if (isOutbound && (d.bizType === 'pilot_service' || d.bizType === 'clinical_application')) {
|
||||
const outboundDetail: OutboundQcDetail = {
|
||||
workOrder: {} as OutboundQcDetail['workOrder'],
|
||||
application: d.application,
|
||||
patient: d.patient,
|
||||
infusionPlan: d.infusionPlan,
|
||||
infusionSchedule: d.infusionSchedule,
|
||||
products: d.products
|
||||
}
|
||||
const variant =
|
||||
d.bizType === 'clinical_application' ? 'clinical_application' : 'pilot_service'
|
||||
sections.push(...buildOutboundPilotContextSections(outboundDetail, variant))
|
||||
return sections
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,13 @@
|
||||
/>
|
||||
</template>
|
||||
<template #product-table>
|
||||
<el-table :data="detail?.products || []" stripe size="small" class="outbound-product-table">
|
||||
<div v-if="detail?.products?.length" class="view-subtable-wrap">
|
||||
<el-table
|
||||
:data="detail?.products || []"
|
||||
stripe
|
||||
size="small"
|
||||
class="list-table view-subtable outbound-product-table"
|
||||
>
|
||||
<el-table-column type="index" label="序号" min-width="60" align="center" />
|
||||
<el-table-column prop="projectCode" label="项目编码" min-width="120" align="center" show-overflow-tooltip />
|
||||
<el-table-column prop="projectName" label="项目名称" min-width="120" align="center" show-overflow-tooltip />
|
||||
@@ -35,6 +41,8 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<p v-else class="view-empty-hint">暂无产品明细</p>
|
||||
</template>
|
||||
<template v-for="task in tasksWithAttachments" #[taskAttachmentSlotName(task.id)]>
|
||||
<div :key="task.id" class="outbound-qc-task-attachments">
|
||||
@@ -469,6 +477,24 @@
|
||||
}
|
||||
|
||||
.outbound-product-table {
|
||||
margin-top: 4px;
|
||||
margin-top: 0;
|
||||
|
||||
:deep(.el-table__header th.el-table__cell),
|
||||
:deep(.el-table__body td.el-table__cell) {
|
||||
font-size: 12px;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
:deep(.el-table__header th.el-table__cell .cell),
|
||||
:deep(.el-table__body td.el-table__cell .cell) {
|
||||
font-size: 12px;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
:deep(.el-tag) {
|
||||
--el-tag-font-size: 11px;
|
||||
height: 20px;
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -2,131 +2,116 @@
|
||||
<!-- eslint-disable vue/no-v-model-argument -->
|
||||
<template>
|
||||
<div class="qc-work-order-task-sublist">
|
||||
<div class="list-toolbar qc-work-order-task-sublist__toolbar">
|
||||
<div class="list-toolbar-row">
|
||||
<el-button class="btn-ghost" size="small" :loading="loading" @click="loadData">
|
||||
<el-icon><RefreshLeft /></el-icon>刷新
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="qc-work-order-task-sublist__body sqxp-subtable-wrap">
|
||||
<el-table
|
||||
class="list-table qc-work-order-task-sublist__table sqxp-subtable"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
stripe
|
||||
size="small"
|
||||
@row-dblclick="handleView"
|
||||
>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
min-width="68"
|
||||
align="center"
|
||||
:index="(i) => i + 1"
|
||||
/>
|
||||
<el-table-column prop="taskNo" label="任务号" min-width="150" align="center" />
|
||||
<el-table-column prop="taskType" label="检测类型" min-width="110" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.taskType === 'sysz' ? 'success' : 'info'" size="small">{{
|
||||
taskTypeLabel(row.taskType)
|
||||
}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="itemName" label="检测项目" min-width="160" align="center" />
|
||||
<el-table-column prop="companyName" label="第三方公司" min-width="120" align="center">
|
||||
<template #default="{ row }">{{ row.companyName || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="conclusion" label="质检结论" min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.conclusion === 'tg'" type="success" size="small">
|
||||
{{ row.conclusionLabel || qcTaskConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
<el-tag v-else-if="row.conclusion === 'btg'" type="danger" size="small">
|
||||
{{ row.conclusionLabel || qcTaskConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
<el-tag v-else type="info" size="small">—</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="taskStatus" label="状态" min-width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag
|
||||
:type="
|
||||
row.taskStatus === 'ywc'
|
||||
? 'success'
|
||||
: row.taskStatus === 'jxz'
|
||||
? 'warning'
|
||||
: 'info'
|
||||
"
|
||||
size="small"
|
||||
>
|
||||
{{ taskStatusLabel(row.taskStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="remark"
|
||||
label="备注"
|
||||
min-width="140"
|
||||
align="center"
|
||||
show-overflow-tooltip
|
||||
<div class="qc-work-order-task-sublist__panel" v-loading="loading">
|
||||
<div v-if="tableData.length" class="qc-task-cards-wrap">
|
||||
<div class="qc-work-order-task-sublist__summary">
|
||||
<span class="qc-work-order-task-sublist__count">共 {{ tableData.length }} 项任务</span>
|
||||
<el-button
|
||||
class="qc-work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<template #default="{ row }">{{ row.remark || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" min-width="260" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<template v-if="hasPrimaryTaskActions(row)">
|
||||
<el-button
|
||||
v-if="canStartTask(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="handleStart(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>开始
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canFillResult(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
@click="openResult(row)"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>填写结果
|
||||
</el-button>
|
||||
</template>
|
||||
<el-button v-else class="btn-op-item primary" @click="handleView(row)">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item">
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPrimaryTaskActions(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div
|
||||
v-for="(row, idx) in tableData"
|
||||
:key="row.id || idx"
|
||||
class="qc-task-card"
|
||||
@dblclick="handleView(row)"
|
||||
>
|
||||
<div class="qc-task-card__head">
|
||||
<span class="qc-task-card__name">{{ row.itemName || row.taskNo || '—' }}</span>
|
||||
<el-tag :type="taskStatusTagType(row.taskStatus)" size="small">
|
||||
{{ taskStatusLabel(row.taskStatus) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="qc-task-card__meta">
|
||||
<span class="qc-task-card__code">{{ row.taskNo || '—' }}</span>
|
||||
<el-tag :type="taskTypeTagType(row.taskType)" size="small">
|
||||
{{ taskTypeLabel(row.taskType) }}
|
||||
</el-tag>
|
||||
<el-tag
|
||||
v-if="row.conclusion === 'tg' || row.conclusion === 'btg'"
|
||||
:type="conclusionTagType(row.conclusion)"
|
||||
size="small"
|
||||
>
|
||||
{{ row.conclusionLabel || qcTaskConclusionLabel(row.conclusion) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="qc-work-order-task-sublist__ops">
|
||||
<template v-if="hasPrimaryTaskActions(row)">
|
||||
<el-button
|
||||
v-if="canStartTask(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleStart(row)"
|
||||
>
|
||||
<el-icon><VideoPlay /></el-icon>开始
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="canFillResult(row)"
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="openResult(row)"
|
||||
>
|
||||
<el-icon><EditPen /></el-icon>填写结果
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button
|
||||
v-else
|
||||
class="btn-op-item primary"
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleView(row)"
|
||||
>
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-button>
|
||||
<el-dropdown
|
||||
v-if="hasMoreTaskActions(row)"
|
||||
trigger="hover"
|
||||
@command="(cmd) => handleDropdownCommand(cmd, row)"
|
||||
>
|
||||
<el-button class="btn-op-item" size="small" @click.stop>
|
||||
<el-icon><More /></el-icon>
|
||||
</el-button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-if="hasPrimaryTaskActions(row)" command="view">
|
||||
<el-icon><View /></el-icon>查看
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="canDeleteTask(row)" command="delete" divided>
|
||||
<el-icon><Delete /></el-icon>删除
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!loading" class="qc-task-cards-wrap qc-task-cards-wrap--empty">
|
||||
<div class="qc-work-order-task-sublist__summary">
|
||||
<el-button
|
||||
class="qc-work-order-task-sublist__refresh-icon"
|
||||
link
|
||||
type="primary"
|
||||
:loading="loading"
|
||||
@click="loadData"
|
||||
>
|
||||
<el-icon><RefreshLeft /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<el-empty
|
||||
v-if="!loading && !tableData.length"
|
||||
class="qc-work-order-task-sublist__empty"
|
||||
description="暂无任务,请先在工单行「配置检测」"
|
||||
:image-size="72"
|
||||
:image-size="56"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
v-model="resultVisible"
|
||||
@@ -607,6 +592,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
function taskStatusTagType(status: string) {
|
||||
if (status === 'ywc') return 'success' as const
|
||||
if (status === 'jxz') return 'warning' as const
|
||||
return 'info' as const
|
||||
}
|
||||
|
||||
function taskTypeTagType(type: string) {
|
||||
return type === 'sysz' ? ('success' as const) : ('info' as const)
|
||||
}
|
||||
|
||||
function conclusionTagType(conclusion: string) {
|
||||
if (conclusion === 'tg') return 'success' as const
|
||||
if (conclusion === 'btg') return 'danger' as const
|
||||
return 'info' as const
|
||||
}
|
||||
|
||||
const resultSubmitLabel = computed(() =>
|
||||
resultTaskStatus.value === 'ywc' ? '保存' : '提交并完成'
|
||||
)
|
||||
@@ -1212,26 +1213,135 @@
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qc-work-order-task-sublist {
|
||||
padding: 12px 16px 16px 40px;
|
||||
padding: 8px 12px 10px 40px;
|
||||
background: #f8fafc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__toolbar {
|
||||
padding: 0 0 8px;
|
||||
border-bottom: none;
|
||||
.qc-work-order-task-sublist__panel {
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__body {
|
||||
display: block;
|
||||
width: 100%;
|
||||
.qc-task-cards-wrap {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__summary {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
padding-top: 8px;
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__count {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
line-height: 1.35;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__refresh-icon {
|
||||
flex-shrink: 0;
|
||||
padding: 0 2px;
|
||||
height: 20px;
|
||||
font-size: 14px;
|
||||
|
||||
.el-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-task-cards-wrap--empty {
|
||||
align-items: center;
|
||||
|
||||
.qc-work-order-task-sublist__summary {
|
||||
padding-top: 0;
|
||||
min-height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__empty {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
padding: 4px 0;
|
||||
|
||||
:deep(.el-empty__description) {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-task-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
flex: 0 0 248px;
|
||||
width: 248px;
|
||||
max-width: 248px;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
cursor: default;
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #a7f3d0;
|
||||
box-shadow: 0 2px 6px rgba(16, 185, 129, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.qc-task-card__head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.qc-task-card__name {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
line-height: 1.35;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.qc-task-card__meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 4px 6px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.qc-task-card__code {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 11px;
|
||||
color: #475569;
|
||||
line-height: 1.35;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.qc-work-order-task-sublist__ops {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
|
||||
Reference in new issue
Block a user