This commit is contained in:
zlwu committed 2026-06-12 15:17:54 +08:00
1 parent 4ea71a1bae
commit 3abe69c1cc
83 files changed
+33505 -21867

No files matched your search

@@ -22,8 +22,14 @@ export interface ProductionWorkOrderItem {
workOrderStatus: string
createTime?: string
remark?: string
labStorageCode?: string
protocolStatus?: string
bizType?: string
bizTypeLabel?: string
/** 出库工单:关联申请单号 */
applicationNo?: string
applicationName?: string
channelName?: string
/** 出库工单:患者/用户姓名 */
patientName?: string
/** 出库工单:当前为第几次输注计划 */
@@ -127,3 +133,31 @@ export function fetchUpdateProductionWorkOrder(id: string, data: { remark?: stri
export function fetchDeleteProductionWorkOrder(id: string) {
return request.del({ url: `/web/admin/production-work-orders/${id}` })
}
export interface ProductionCellProductOption {
id: string
cellProductId?: string
productCode?: string
productName?: string
productTypeName?: string
passage?: string
storageSlotName?: string
taskId?: string
taskNo?: string
}
export function fetchProductionWorkOrderCellProductOptions(workOrderId: string) {
return request.get<ProductionCellProductOption[]>({
url: `/web/admin/production-work-orders/${workOrderId}/cell-product-options`
})
}
export function fetchCreateQcFromProduction(
workOrderId: string,
data: { cellProductId: string; productionTaskId?: string; remark?: string }
) {
return request.post({
url: `/web/admin/production-work-orders/${workOrderId}/qc-work-orders`,
data
})
}
+43
View File
@@ -15,6 +15,38 @@ export type SampleReceptionCheckResult = {
checkItemId?: string
}
export type QcProtocolPaymentDetailSummary = {
installmentNo?: number | null
installmentLabel?: string
installmentDueDate?: string
dueAmount?: number | null
transferAmount?: number | null
payStatus?: string
payStatusLabel?: string
}
export type QcProtocolPaymentSummary = {
payMode?: string
payModeLabel?: string
contractAmount?: number | null
receivedAmount?: number | null
pendingAmount?: number | null
statusHint?: string
overallPayStatus?: string
overallPayStatusLabel?: string
overallPayStatusTagType?: string
installmentCount?: number | null
paymentDetails?: QcProtocolPaymentDetailSummary[]
}
export type QcBasicExperimentFeeSummary = {
saleAmount?: number | null
paymentAmount?: number | null
transferAmount?: number | null
payStatus?: string
payStatusLabel?: string
}
export type QcWorkOrderReceptionDetail = {
protocolNo?: string
sampleCode?: string
@@ -93,6 +125,15 @@ export type QcWorkOrder = {
/** 出库工单:输注计划总次数 */
totalCourseCount?: number | null
infusionTime?: string
triggerSource?: string
triggerSourceLabel?: string
productionWorkOrderId?: string
productionWorkOrderNo?: string
productionTaskId?: string
protocolStatus?: string
protocolStatusLabel?: string
paymentSummary?: QcProtocolPaymentSummary | null
feeSummary?: QcBasicExperimentFeeSummary | null
}
export type QcWorkOrderDetail = QcWorkOrder & {
@@ -139,6 +180,7 @@ export function fetchQcWorkOrderList(params?: {
createTimeEnd?: string
infusionTimeStart?: string
infusionTimeEnd?: string
triggerSource?: string
}) {
return request.get<PageList<QcWorkOrder>>({
url: '/web/admin/qc-work-orders',
@@ -249,6 +291,7 @@ export type OutboundQcDetailProduct = {
export type OutboundQcDetail = {
workOrder: QcWorkOrderDetail
feeSummary?: QcBasicExperimentFeeSummary | null
application?: OutboundQcDetailApplication
patient?: OutboundQcDetailPatient
infusionPlan?: OutboundQcDetailInfusionPlan
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "label": "qc-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1"}, {"id": "api_qc_work_order_fetchqcworkorderlist", "label": "fetchQcWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L160"}, {"id": "api_qc_work_order_fetchqcworkorderdetail", "label": "fetchQcWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L179"}, {"id": "api_qc_work_order_fetchconfigureqcworkorder", "label": "fetchConfigureQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L185"}, {"id": "api_qc_work_order_fetchcreateqcworkorder", "label": "fetchCreateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L202"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L217"}, {"id": "api_qc_work_order_fetchdeleteqcworkorder", "label": "fetchDeleteQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L227"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L291"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L160", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L179", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchconfigureqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L185", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchcreateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L202", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L217", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchdeleteqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L227", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L291", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_qc_work_order_fetchqcworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L173"}, {"caller_nid": "api_qc_work_order_fetchqcworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L180"}, {"caller_nid": "api_qc_work_order_fetchconfigureqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L196"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine truncated
@@ -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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L511"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L516"}, {"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": "L972"}, {"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": "L977"}, {"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": "L981"}, {"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": "L988"}, {"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": "L993"}, {"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": "L1009"}, {"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": "L1015"}, {"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": "L1026"}, {"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": "L1115"}, {"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": "L1133"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L459", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L460", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L461", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L462", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersamplegroup_vue", "label": "QcWorkOrderSampleGroup.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSampleGroup.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "label": "QcWorkOrderFeeSummaryBar.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L63", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_money_format", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L67", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L68", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderfeesummarybar_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_status_tag_registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderFeeSummaryBar.vue", "source_location": "L69", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_productionworkordercardlist_vue", "label": "ProductionWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L1"}, {"id": "production_work_order_productionworkordercardlist_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L280"}, {"id": "production_work_order_productionworkordercardlist_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L284"}, {"id": "production_work_order_productionworkordercardlist_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L288"}, {"id": "production_work_order_productionworkordercardlist_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L292"}, {"id": "production_work_order_productionworkordercardlist_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L296"}, {"id": "production_work_order_productionworkordercardlist_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L302"}, {"id": "production_work_order_productionworkordercardlist_productionwostatustag", "label": "productionWoStatusTag()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L322"}, {"id": "production_work_order_productionworkordercardlist_handlecardselect", "label": "handleCardSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L332"}, {"id": "production_work_order_productionworkordercardlist_cardindex", "label": "cardIndex()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L336"}, {"id": "production_work_order_productionworkordercardlist_isselected", "label": "isSelected()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L340"}, {"id": "production_work_order_productionworkordercardlist_candispatchtask", "label": "canDispatchTask()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L344"}, {"id": "production_work_order_productionworkordercardlist_candispatchqc", "label": "canDispatchQc()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L348"}, {"id": "production_work_order_productionworkordercardlist_dispatchqctooltip", "label": "dispatchQcTooltip()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L354"}, {"id": "production_work_order_productionworkordercardlist_cancomplete", "label": "canComplete()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L361"}, {"id": "production_work_order_productionworkordercardlist_candeleteworkorder", "label": "canDeleteWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/ProductionWorkOrderCardList.vue", "source_location": "L365"}, {"id": "production_work_order_productionworkordercardlist_hasmoreactions", "label": "hasMoreActions()", "file_type": "code", "source_file":Line truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "label": "OutboundQcViewDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L1"}, {"id": "qc_work_order_outboundqcviewdialog_handledownload", "label": "handleDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L296"}, {"id": "qc_work_order_outboundqcviewdialog_taskattachmentslotname", "label": "taskAttachmentSlotName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L309"}, {"id": "qc_work_order_outboundqcviewdialog_taskmaterialslotname", "label": "taskMaterialSlotName()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L313"}, {"id": "qc_work_order_outboundqcviewdialog_handletaskpreview", "label": "handleTaskPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L317"}, {"id": "qc_work_order_outboundqcviewdialog_handletaskdownload", "label": "handleTaskDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L322"}, {"id": "qc_work_order_outboundqcviewdialog_conclusiontagtype", "label": "conclusionTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L328"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_handledownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L296", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_taskattachmentslotname", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L309", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_taskmaterialslotname", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L313", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_handletaskpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L317", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_handletaskdownload", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L322", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_outboundqcviewdialog_vue", "target": "qc_work_order_outboundqcviewdialog_conclusiontagtype", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L328", "weight": 1.0}], "raw_calls": [{"caller_nid": "qc_work_order_outboundqcviewdialog_handledownload", "callee": "downloadAttachmentFile", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_location": "L297"}, {"caller_nid": "qc_work_order_outboundqcviewdialog_handletaskpreview", "callee": "fullUrl", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/OutboundQcViewDialog.vue", "source_locatLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "label": "QcWorkOrderSingleCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L311"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L315"}, {"id": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L319"}, {"id": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L323"}, {"id": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L327"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L332"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L338"}, {"id": "qc_work_order_qcworkordersinglecard_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L344"}, {"id": "qc_work_order_qcworkordersinglecard_formatqctarget", "label": "formatQcTarget()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L351"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L311", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L315", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L319", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L323", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspectioLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "label": "qc-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1"}, {"id": "api_qc_work_order_fetchqcworkorderlist", "label": "fetchQcWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L138"}, {"id": "api_qc_work_order_fetchqcworkorderdetail", "label": "fetchQcWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L157"}, {"id": "api_qc_work_order_fetchconfigureqcworkorder", "label": "fetchConfigureQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L163"}, {"id": "api_qc_work_order_fetchcreateqcworkorder", "label": "fetchCreateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L180"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L195"}, {"id": "api_qc_work_order_fetchdeleteqcworkorder", "label": "fetchDeleteQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L205"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L268"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L138", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L157", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchconfigureqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L163", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchcreateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L180", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L195", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchdeleteqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L205", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L268", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_qc_work_order_fetchqcworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L151"}, {"caller_nid": "api_qc_work_order_fetchqcworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L158"}, {"caller_nid": "api_qc_work_order_fetchconfigureqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L174"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "label": "qc-work-order-groups.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L1"}, {"id": "utils_qc_work_order_groups_triggersortweight", "label": "triggerSortWeight()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L9"}, {"id": "utils_qc_work_order_groups_sortworkordersingroup", "label": "sortWorkOrdersInGroup()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L13"}, {"id": "utils_qc_work_order_groups_groupinboundqcworkorders", "label": "groupInboundQcWorkOrders()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L22"}, {"id": "utils_qc_work_order_groups_triggersourcetablabel", "label": "triggerSourceTabLabel()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L40"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_triggersortweight", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L9", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_sortworkordersingroup", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L13", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_groupinboundqcworkorders", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L22", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups_ts", "target": "utils_qc_work_order_groups_triggersourcetablabel", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L40", "weight": 1.0}], "raw_calls": [{"caller_nid": "utils_qc_work_order_groups_sortworkordersingroup", "callee": "sort", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L14"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "trim", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L25"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L26"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "push", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L27"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "set", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L28"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "map", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L30"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "from", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L30"}, {"caller_nid": "utils_qc_work_order_groups_groupinboundqcworkorders", "callee": "entries", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-groups.ts", "source_location": "L30"}]}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "label": "QcWorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "label": "isCurrentUserAssignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L708"}, {"id": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "label": "nextMaterialRowKey()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L736"}, {"id": "qc_work_order_qcworkordertasksublist_onrequisitionselect", "label": "onRequisitionSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L900"}, {"id": "qc_work_order_qcworkordertasksublist_addmaterialrow", "label": "addMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L928"}, {"id": "qc_work_order_qcworkordertasksublist_removematerialrow", "label": "removeMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L942"}, {"id": "qc_work_order_qcworkordertasksublist_materialrowsfromapi", "label": "materialRowsFromApi()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L946"}, {"id": "qc_work_order_qcworkordertasksublist_enrichmaterialusagerows", "label": "enrichMaterialUsageRows()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L966"}, {"id": "qc_work_order_qcworkordertasksublist_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1065"}, {"id": "qc_work_order_qcworkordertasksublist_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1069"}, {"id": "qc_work_order_qcworkordertasksublist_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1077"}, {"id": "qc_work_order_qcworkordertasksublist_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1083"}, {"id": "qc_work_order_qcworkordertasksublist_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1087"}, {"id": "qc_work_order_qcworkordertasksublist_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1091"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L708", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L736", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_orderLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "label": "QcWorkOrderSingleCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersamplegroup_vue", "label": "QcWorkOrderSampleGroup.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSampleGroup.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkorderprotocolpaymentpanel_vue", "label": "QcWorkOrderProtocolPaymentPanel.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderProtocolPaymentPanel.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_workordertasksublist_vue", "label": "WorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/WorkOrderTaskSubList.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L512"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L517"}, {"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": "L936"}, {"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": "L941"}, {"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": "L945"}, {"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": "L952"}, {"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": "L957"}, {"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": "L973"}, {"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": "L979"}, {"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": "L990"}, {"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": "L1079"}, {"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": "L1097"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L462", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L463", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L464", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L465", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "relLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}
@@ -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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L508"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L513"}, {"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": "L931"}, {"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": "L936"}, {"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": "L940"}, {"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": "L947"}, {"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": "L952"}, {"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": "L968"}, {"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": "L974"}, {"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": "L985"}, {"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": "L1074"}, {"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": "L1092"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L458", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L459", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L460", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L461", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "relLine truncated
@@ -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_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L496"}, {"id": "qc_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L501"}, {"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": "L914"}, {"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": "L919"}, {"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": "L923"}, {"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": "L930"}, {"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": "L935"}, {"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": "L951"}, {"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": "L957"}, {"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": "L968"}, {"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": "L1057"}, {"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": "L1075"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L447", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L448", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L449", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_lab_test_item", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/index.vue", "source_location": "L457", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_index_vue", "target": "users_wuzilong_woLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "label": "DispatchQcWorkOrderDialog.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L79", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L80", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L81", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_dispatchqcworkorderdialog_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchQcWorkOrderDialog.vue", "source_location": "L82", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "label": "QcWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordercardlist_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L281"}, {"id": "qc_work_order_qcworkordercardlist_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L285"}, {"id": "qc_work_order_qcworkordercardlist_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L289"}, {"id": "qc_work_order_qcworkordercardlist_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L293"}, {"id": "qc_work_order_qcworkordercardlist_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L298"}, {"id": "qc_work_order_qcworkordercardlist_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L304"}, {"id": "qc_work_order_qcworkordercardlist_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L310"}, {"id": "qc_work_order_qcworkordercardlist_workorderstatustagtype", "label": "workOrderStatusTagType()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L317"}, {"id": "qc_work_order_qcworkordercardlist_cardindex", "label": "cardIndex()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L324"}, {"id": "qc_work_order_qcworkordercardlist_canconfigureworkorder", "label": "canConfigureWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L328"}, {"id": "qc_work_order_qcworkordercardlist_canedittemporaryworkorder", "label": "canEditTemporaryWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L332"}, {"id": "qc_work_order_qcworkordercardlist_caneditremarkworkorder", "label": "canEditRemarkWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L339"}, {"id": "qc_work_order_qcworkordercardlist_candeleteworkorder", "label": "canDeleteWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L352"}, {"id": "qc_work_order_qcworkordercardlist_hasmoreworkorderactions", "label": "hasMoreWorkOrderActions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L360"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "qc_work_order_qcworkordercardlist_protocolstatustagtypebysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L281", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "qc_work_order_qcworkordercardlist_shouldshowtempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "label": "qc-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1"}, {"id": "api_qc_work_order_fetchqcworkorderlist", "label": "fetchQcWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L172"}, {"id": "api_qc_work_order_fetchqcworkorderdetail", "label": "fetchQcWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L191"}, {"id": "api_qc_work_order_fetchconfigureqcworkorder", "label": "fetchConfigureQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L197"}, {"id": "api_qc_work_order_fetchcreateqcworkorder", "label": "fetchCreateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L214"}, {"id": "api_qc_work_order_fetchupdateqcworkorder", "label": "fetchUpdateQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L229"}, {"id": "api_qc_work_order_fetchdeleteqcworkorder", "label": "fetchDeleteQcWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L239"}, {"id": "api_qc_work_order_fetchoutboundqcdetail", "label": "fetchOutboundQcDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L303"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L172", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchqcworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L191", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchconfigureqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L197", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchcreateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L214", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchupdateqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L229", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchdeleteqcworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L239", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order_ts", "target": "api_qc_work_order_fetchoutboundqcdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L303", "weight": 1.0}], "raw_calls": [{"caller_nid": "api_qc_work_order_fetchqcworkorderlist", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L185"}, {"caller_nid": "api_qc_work_order_fetchqcworkorderdetail", "callee": "get", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L192"}, {"caller_nid": "api_qc_work_order_fetchconfigureqcworkorder", "callee": "post", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-work-order.ts", "source_location": "L208"}, {"caller_nid": "api_qc_work_order_fetchcreateqcworkoLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "label": "QcWorkOrderTaskSubList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "label": "isCurrentUserAssignee()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L615"}, {"id": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "label": "nextMaterialRowKey()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L643"}, {"id": "qc_work_order_qcworkordertasksublist_onrequisitionselect", "label": "onRequisitionSelect()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L807"}, {"id": "qc_work_order_qcworkordertasksublist_addmaterialrow", "label": "addMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L835"}, {"id": "qc_work_order_qcworkordertasksublist_removematerialrow", "label": "removeMaterialRow()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L849"}, {"id": "qc_work_order_qcworkordertasksublist_materialrowsfromapi", "label": "materialRowsFromApi()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L853"}, {"id": "qc_work_order_qcworkordertasksublist_enrichmaterialusagerows", "label": "enrichMaterialUsageRows()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L873"}, {"id": "qc_work_order_qcworkordertasksublist_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L972"}, {"id": "qc_work_order_qcworkordertasksublist_normalizeresultparams", "label": "normalizeResultParams()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L976"}, {"id": "qc_work_order_qcworkordertasksublist_toresultnumber", "label": "toResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L984"}, {"id": "qc_work_order_qcworkordertasksublist_setresultnumber", "label": "setResultNumber()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L990"}, {"id": "qc_work_order_qcworkordertasksublist_hasresultvalue", "label": "hasResultValue()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L994"}, {"id": "qc_work_order_qcworkordertasksublist_formatmetric", "label": "formatMetric()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L998"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_iscurrentuserassignee", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L615", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworkordertasksublist_nextmaterialrowkey", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderTaskSubList.vue", "source_location": "L643", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordertasksublist_vue", "target": "qc_work_order_qcworLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "label": "production-work-order.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L1"}, {"id": "api_production_work_order_fetchproductionworkorderlist", "label": "fetchProductionWorkOrderList()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L69"}, {"id": "api_production_work_order_fetchproductionworkorderdetail", "label": "fetchProductionWorkOrderDetail()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L89"}, {"id": "api_production_work_order_fetchcompleteproductionworkorder", "label": "fetchCompleteProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L93"}, {"id": "api_production_work_order_fetchcreateproductionworkorder", "label": "fetchCreateProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L97"}, {"id": "api_production_work_order_fetchconfigureproductionworkorder", "label": "fetchConfigureProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L110"}, {"id": "api_production_work_order_fetchupdateproductionworkorder", "label": "fetchUpdateProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L126"}, {"id": "api_production_work_order_fetchdeleteproductionworkorder", "label": "fetchDeleteProductionWorkOrder()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L133"}, {"id": "api_production_work_order_fetchproductionworkordercellproductoptions", "label": "fetchProductionWorkOrderCellProductOptions()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L149"}, {"id": "api_production_work_order_fetchcreateqcfromproduction", "label": "fetchCreateQcFromProduction()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L155"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L1", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L2", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchproductionworkorderlist", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L69", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchproductionworkorderdetail", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L89", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchcompleteproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L93", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchcreateproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "source_location": "L97", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order_ts", "target": "api_production_work_order_fetchconfigureproductionworkorder", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-work-order.ts", "soLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L1"}, {"id": "production_work_order_index_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L331"}, {"id": "production_work_order_index_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L336"}, {"id": "production_work_order_index_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L343"}, {"id": "production_work_order_index_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L346"}, {"id": "production_work_order_index_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L350"}, {"id": "production_work_order_index_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L356"}, {"id": "production_work_order_index_handleadd", "label": "handleAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L429"}, {"id": "production_work_order_index_handletypetabchange", "label": "handleTypeTabChange()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L437"}, {"id": "production_work_order_index_submitadd", "label": "submitAdd()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L443"}, {"id": "production_work_order_index_handlereceptionattachmentpreview", "label": "handleReceptionAttachmentPreview()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L706"}, {"id": "production_work_order_index_handlereceptionattachmentdownload", "label": "handleReceptionAttachmentDownload()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L710"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "vue_router", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L286", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "element_plus", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L287", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "icons_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L288", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_production_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue", "source_location": "L298", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_production_work_order_index_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_labels", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-oLine truncated
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "label": "QcWorkOrderCardList.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L1"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_qc_work_order", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L56", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_qc_work_order_groups", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L57", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersamplegroup_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L58", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordercardlist_vue", "target": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderCardList.vue", "source_location": "L59", "weight": 1.0}], "raw_calls": []}
@@ -0,0 +1 @@
{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "label": "QcWorkOrderSingleCard.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L1"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "label": "protocolStatusLabelBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L298"}, {"id": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "label": "protocolStatusTagTypeBySource()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L302"}, {"id": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "label": "shouldShowTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L306"}, {"id": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "label": "formatTempEmptyField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L310"}, {"id": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "label": "formatTempCellProductField()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L314"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundschedulesortno", "label": "formatOutboundScheduleSortNo()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L319"}, {"id": "qc_work_order_qcworkordersinglecard_formatoutboundscheduletotalcount", "label": "formatOutboundScheduleTotalCount()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L325"}, {"id": "qc_work_order_qcworkordersinglecard_formatdetectmethods", "label": "formatDetectMethods()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L331"}, {"id": "qc_work_order_qcworkordersinglecard_formatqctarget", "label": "formatQcTarget()", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L338"}], "edges": [{"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatuslabelbysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L298", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_protocolstatustagtypebysource", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L302", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_shouldshowtempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L306", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempemptyfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-work-order/QcWorkOrderSingleCard.vue", "source_location": "L310", "weight": 1.0}, {"source": "users_wuzilong_work_00code_zkxw_web_admin_src_views_quality_inspection_qc_work_order_qcworkordersinglecard_vue", "target": "qc_work_order_qcworkordersinglecard_formattempcellproductfield", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspectioLine truncated
@@ -0,0 +1,42 @@
import type { QcWorkOrder } from '@/api/qc-work-order'
export type QcWorkOrderSampleGroupModel = {
groupKey: string
sampleCode: string
workOrders: QcWorkOrder[]
}
function triggerSortWeight(row: QcWorkOrder) {
return (row.triggerSource || 'reception') === 'reception' ? 0 : 1
}
function sortWorkOrdersInGroup(rows: QcWorkOrder[]) {
return [...rows].sort((a, b) => {
const byTrigger = triggerSortWeight(a) - triggerSortWeight(b)
if (byTrigger !== 0) return byTrigger
return String(a.createTime || '').localeCompare(String(b.createTime || ''))
})
}
/** 入库 Tab:按样本编码分组(前端分组,分页仍按工单条数) */
export function groupInboundQcWorkOrders(rows: QcWorkOrder[]): QcWorkOrderSampleGroupModel[] {
const map = new Map<string, QcWorkOrder[]>()
for (const row of rows) {
const key = (row.sampleCode || '').trim() || row.id
const list = map.get(key)
if (list) list.push(row)
else map.set(key, [row])
}
return Array.from(map.entries()).map(([groupKey, workOrders]) => {
const sorted = sortWorkOrdersInGroup(workOrders)
return {
groupKey,
sampleCode: sorted[0]?.sampleCode || '',
workOrders: sorted
}
})
}
export function triggerSourceTabLabel(row: QcWorkOrder) {
return row.triggerSourceLabel || ((row.triggerSource || 'reception') === 'production' ? '生产过程' : '样本接收')
}
@@ -0,0 +1,206 @@
<!-- 生产工单 · 派发质检工单弹窗 -->
<template>
<el-dialog
v-model="dialogVisible"
title="派发质检工单"
width="560px"
class="dialog-form-layout"
align-center
append-to-body
destroy-on-close
:close-on-click-modal="false"
@close="handleClose"
>
<div class="dispatch-qc-dialog-work-order-info">
<span
>工单号:<b>{{ workOrderRow?.workOrderNo || '—' }}</b></span
>
<span>样本编码:{{ workOrderRow?.sampleCode || '—' }}</span>
</div>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-position="top"
class="dialog-form-layout"
v-loading="optionsLoading"
>
<div class="form-grid-2">
<el-form-item label="细胞产品" prop="cellProductId" class="form-col-span-2">
<el-select
v-model="form.cellProductId"
placeholder="请选择细胞产品"
filterable
style="width: 100%"
:disabled="!productOptions.length"
>
<el-option
v-for="opt in productOptions"
:key="opt.id"
:label="formatProductOptionLabel(opt)"
:value="opt.id"
/>
</el-select>
<p v-if="!optionsLoading && !productOptions.length" class="hint-muted">
暂无产出细胞产品,请先完成生产任务并录入输出。
</p>
</el-form-item>
<el-form-item label="备注" class="form-col-span-2">
<el-input
v-model="form.remark"
type="textarea"
:rows="3"
placeholder="选填"
maxlength="512"
show-word-limit
/>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button class="btn-ghost" @click="handleClose">
<el-icon><Close /></el-icon>取消
</el-button>
<el-button
class="btn-main"
type="primary"
:loading="submitting"
:disabled="!productOptions.length"
@click="handleSubmit"
>
<el-icon><Check /></el-icon>确定
</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, watch, computed } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import { Close, Check } from '@element-plus/icons-vue'
import {
fetchProductionWorkOrderCellProductOptions,
fetchCreateQcFromProduction,
type ProductionWorkOrderItem,
type ProductionCellProductOption
} from '@/api/production-work-order'
defineOptions({ name: 'DispatchQcWorkOrderDialog' })
const props = defineProps<{
visible: boolean
workOrderRow: ProductionWorkOrderItem | null
}>()
const emit = defineEmits<{
'update:visible': [val: boolean]
success: [payload: { sampleCode?: string }]
}>()
const dialogVisible = computed({
get: () => props.visible,
set: (v) => emit('update:visible', v)
})
const formRef = ref<FormInstance>()
const form = reactive({ cellProductId: '', remark: '' })
const rules: FormRules = {
cellProductId: [{ required: true, message: '请选择细胞产品', trigger: 'change' }]
}
const productOptions = ref<ProductionCellProductOption[]>([])
const optionsLoading = ref(false)
const submitting = ref(false)
function formatProductOptionLabel(opt: ProductionCellProductOption) {
const parts = [
opt.productCode,
opt.productName,
opt.productTypeName ? `(${opt.productTypeName})` : '',
opt.passage ? `P${opt.passage}` : '',
opt.storageSlotName ? `@${opt.storageSlotName}` : ''
].filter(Boolean)
const base = parts.join(' ') || opt.id
return opt.taskNo ? `${base} · ${opt.taskNo}` : base
}
async function loadOptions() {
if (!props.workOrderRow?.id) {
productOptions.value = []
return
}
optionsLoading.value = true
try {
productOptions.value = (await fetchProductionWorkOrderCellProductOptions(props.workOrderRow.id)) || []
} finally {
optionsLoading.value = false
}
}
function resetForm() {
form.cellProductId = ''
form.remark = ''
formRef.value?.clearValidate()
}
function handleClose() {
dialogVisible.value = false
resetForm()
}
async function handleSubmit() {
if (!props.workOrderRow?.id) return
await formRef.value?.validate()
submitting.value = true
try {
const selected = productOptions.value.find((o) => o.id === form.cellProductId)
await fetchCreateQcFromProduction(props.workOrderRow.id, {
cellProductId: form.cellProductId,
productionTaskId: selected?.taskId,
remark: form.remark || undefined
})
ElMessage.success('质检工单派发成功')
emit('success', { sampleCode: props.workOrderRow.sampleCode })
handleClose()
} finally {
submitting.value = false
}
}
watch(
() => [props.visible, props.workOrderRow?.id] as const,
([visible]) => {
if (visible) {
resetForm()
loadOptions()
}
}
)
</script>
<style scoped lang="scss">
.dispatch-qc-dialog-work-order-info {
display: flex;
flex-wrap: wrap;
gap: 8px 20px;
margin-bottom: 12px;
padding: 10px 12px;
font-size: 13px;
color: #64748b;
background: #f8fafc;
border-radius: 8px;
border: 1px solid #e2e8f0;
b {
color: #1e293b;
font-weight: 600;
}
}
.hint-muted {
margin: 6px 0 0;
font-size: 12px;
color: var(--mint-text-muted, #94a3b8);
line-height: 1.4;
}
</style>
@@ -0,0 +1,496 @@
<!-- 生产工单 · 卡片列表(单列 + 内嵌生产任务) -->
<template>
<div class="list-body list-wrap production-work-order-cards-body">
<div v-loading="loading" class="production-work-order-cards-wrap">
<article v-for="(row, idx) in rows" :key="row.id" class="production-work-order-card">
<header class="production-work-order-card__head">
<div class="production-work-order-card__head-main">
<div class="production-work-order-card__title-row">
<el-checkbox
:model-value="isSelected(row.id)"
class="production-work-order-card__checkbox"
@change="(val) => handleCardSelect(row, Boolean(val))"
/>
<span class="production-work-order-card__index">{{ cardIndex(idx) }}</span>
<span class="production-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
<el-tag :type="productionWoStatusTag(row.workOrderStatus).type" size="small">
{{ productionWoStatusTag(row.workOrderStatus).label }}
</el-tag>
</div>
<dl class="production-work-order-card__meta">
<template v-if="activeTypeTab === 'outbound'">
<div class="production-work-order-card__meta-item">
<dt>业务类型</dt>
<dd>
<el-tag
:type="
row.bizType === 'pilot_service'
? 'primary'
: row.bizType === 'clinical_application'
? 'warning'
: 'info'
"
size="small"
>
{{ row.bizTypeLabel || '—' }}
</el-tag>
</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>申请单号</dt>
<dd>{{ row.applicationNo || '—' }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>用户名称</dt>
<dd>{{ row.patientName || '—' }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>第几次</dt>
<dd>{{ formatOutboundScheduleSortNo(row) }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>总次数</dt>
<dd>{{ formatOutboundScheduleTotalCount(row) }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>申请单名称</dt>
<dd>{{ row.applicationName || '—' }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>渠道名称</dt>
<dd>{{ row.channelName || '—' }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>输注时间</dt>
<dd>{{ row.infusionTime || '—' }}</dd>
</div>
</template>
<template v-else-if="activeTypeTab === 'temporary'">
<div class="production-work-order-card__meta-item">
<dt>备注</dt>
<dd>{{ row.remark || '—' }}</dd>
</div>
</template>
<template v-else>
<div class="production-work-order-card__meta-item">
<dt>样本编码</dt>
<dd>{{ formatTempEmptyField(row, row.sampleCode) }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>实验室入库编码</dt>
<dd>{{ formatTempEmptyField(row, row.labStorageCode) }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>来源类型</dt>
<dd>
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
<el-tag
v-else
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
size="small"
>
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
</el-tag>
</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>协议状态</dt>
<dd>
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
<el-tag
v-else
:type="
protocolStatusTagTypeBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
"
size="small"
>
{{
protocolStatusLabelBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
}}
</el-tag>
</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>样本类型</dt>
<dd>{{ row.sampleTypeName || '—' }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>接收经手人</dt>
<dd>{{ row.handlerName || '—' }}</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>是否超24小时</dt>
<dd>
<span v-if="!row.receptionTime">—</span>
<el-tag v-else :type="receptionOver24HoursTag(row.receptionTime).type" size="small">
{{ receptionOver24HoursTag(row.receptionTime).label }}
</el-tag>
</dd>
</div>
<div class="production-work-order-card__meta-item">
<dt>接收时间</dt>
<dd>{{ row.receptionTime || '—' }}</dd>
</div>
</template>
<div class="production-work-order-card__meta-item">
<dt>创建时间</dt>
<dd>{{ row.createTime || '—' }}</dd>
</div>
<div
v-if="row.remark && activeTypeTab !== 'temporary'"
class="production-work-order-card__meta-item production-work-order-card__meta-item--wide"
>
<dt>备注</dt>
<dd>{{ row.remark }}</dd>
</div>
</dl>
</div>
<div class="production-work-order-card__ops">
<el-button
v-if="canDispatchTask(row)"
class="btn-op-item primary"
type="primary"
@click="emit('dispatch', row)"
>
<el-icon><Position /></el-icon>派发任务
</el-button>
<el-button v-else class="btn-op-item primary" @click="emit('view', row)">
<el-icon><View /></el-icon>查看
</el-button>
<el-tooltip
v-if="activeTypeTab === 'inbound'"
:content="dispatchQcTooltip(row)"
:disabled="canDispatchQc(row)"
placement="top"
>
<span>
<el-button
class="btn-op-item"
:disabled="!canDispatchQc(row)"
@click="emit('dispatch-qc', row)"
>
<el-icon><Document /></el-icon>派发质检工单
</el-button>
</span>
</el-tooltip>
<el-button v-if="canComplete(row)" class="btn-op-item" @click="emit('complete', row)">
<el-icon><Check /></el-icon>完成工单
</el-button>
<el-dropdown
v-if="hasMoreActions(row)"
trigger="hover"
@command="(cmd) => emit('command', 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="canDispatchTask(row)" command="view">
<el-icon><View /></el-icon>查看
</el-dropdown-item>
<el-dropdown-item command="edit">
<el-icon><EditPen /></el-icon>编辑
</el-dropdown-item>
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
<el-icon><Delete /></el-icon>删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</header>
<section class="production-work-order-card__tasks">
<WorkOrderTaskSubList
embedded
:work-order="row"
:refresh-token="taskRefreshToken"
@changed="emit('tasks-changed')"
/>
</section>
</article>
<el-empty
v-if="!loading && !rows.length"
class="production-work-order-cards-empty"
description="暂无生产工单"
:image-size="72"
/>
</div>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="page"
:page-size="pageSize"
:total="total"
layout="total, sizes, prev, pager, next"
@size-change="(v) => emit('page-size-change', v)"
@current-change="(v) => emit('page-change', v)"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { View, Position, Document, Check, More, EditPen, Delete } from '@element-plus/icons-vue'
import type { ProductionWorkOrderItem } from '@/api/production-work-order'
import { receptionSourceLabel } from '@/utils/qc-labels'
import {
protocolStatusLabel,
protocolStatusTagType,
donationStatusLabel,
donationStatusTagType
} from '@/utils/status-tag-registry'
import type { TagType } from '@/utils/status-tag-registry'
import WorkOrderTaskSubList from './WorkOrderTaskSubList.vue'
defineOptions({ name: 'ProductionWorkOrderCardList' })
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound'
const props = defineProps<{
rows: ProductionWorkOrderItem[]
loading: boolean
activeTypeTab: WorkOrderTypeTab
page: number
pageSize: number
total: number
taskRefreshToken: number
selectedIds: string[]
}>()
const emit = defineEmits<{
view: [row: ProductionWorkOrderItem]
dispatch: [row: ProductionWorkOrderItem]
'dispatch-qc': [row: ProductionWorkOrderItem]
complete: [row: ProductionWorkOrderItem]
command: [cmd: string, row: ProductionWorkOrderItem]
'toggle-select': [row: ProductionWorkOrderItem, checked: boolean]
'tasks-changed': []
'page-change': [page: number]
'page-size-change': [size: number]
}>()
const RECEPTION_OVER_HOURS_MS = 24 * 60 * 60 * 1000
function protocolStatusLabelBySource(status: string, source: string): string {
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
}
function protocolStatusTagTypeBySource(status: string, source: string): TagType {
return source === 'research_donation' ? donationStatusTagType(status) : protocolStatusTagType(status)
}
function shouldShowTempEmptyField(row: ProductionWorkOrderItem, value?: string | null) {
return row.workOrderType === 'temporary' && !String(value || '').trim()
}
function formatTempEmptyField(row: ProductionWorkOrderItem, value?: string | null) {
return shouldShowTempEmptyField(row, value) ? '—' : String(value || '')
}
function formatOutboundScheduleSortNo(row: Record<string, unknown>) {
const n = row.sortNo ?? row.orderNum
if (n == null || n === '' || Number(n) <= 0) return '—'
return `第${Number(n)}次`
}
function formatOutboundScheduleTotalCount(row: Record<string, unknown>) {
const n = row.totalCourseCount
if (n == null || n === '' || Number(n) <= 0) return '—'
return `共${Number(n)}次`
}
function parseReceptionTime(value?: string | null): Date | null {
const s = String(value || '').trim()
if (!s) return null
const dt = new Date(s.replace(/-/g, '/'))
return Number.isNaN(dt.getTime()) ? null : dt
}
function receptionOver24HoursTag(receptionTime?: string | null): { label: string; type: TagType } {
const dt = parseReceptionTime(receptionTime)
if (!dt) return { label: '—', type: 'info' }
if (Date.now() - dt.getTime() > RECEPTION_OVER_HOURS_MS) return { label: '是', type: 'danger' }
return { label: '否', type: 'success' }
}
function productionWoStatusTag(status: string): { label: string; type: TagType } {
const map: Record<string, { label: string; type: TagType }> = {
dpz: { label: '待配置', type: 'info' },
jxz: { label: '进行中', type: 'warning' },
ywc: { label: '已完成', type: 'success' },
yzf: { label: '已作废', type: 'danger' }
}
return map[status] || { label: status, type: 'info' }
}
function handleCardSelect(row: ProductionWorkOrderItem, checked: boolean) {
emit('toggle-select', row, checked)
}
function cardIndex(i: number) {
return (props.page - 1) * props.pageSize + i + 1
}
function isSelected(id: string) {
return props.selectedIds.includes(id)
}
function canDispatchTask(row: ProductionWorkOrderItem) {
return row.workOrderStatus === 'dpz' || row.workOrderStatus === 'jxz'
}
function canDispatchQc(row: ProductionWorkOrderItem) {
if (props.activeTypeTab !== 'inbound') return false
if (row.workOrderStatus === 'yzf') return false
return row.workOrderStatus === 'jxz' || row.workOrderStatus === 'ywc'
}
function dispatchQcTooltip(row: ProductionWorkOrderItem) {
if (props.activeTypeTab !== 'inbound') return ''
if (row.workOrderStatus === 'dpz') return '请先派发并完成生产任务,录入输出细胞产品后再派发质检'
if (row.workOrderStatus === 'yzf') return '已作废工单不可派发质检'
return '请先完成生产任务并录入输出细胞产品'
}
function canComplete(row: ProductionWorkOrderItem) {
return row.workOrderStatus === 'dpz' || row.workOrderStatus === 'jxz'
}
function canDeleteWorkOrder(row: ProductionWorkOrderItem) {
return props.activeTypeTab !== 'outbound' && row.workOrderStatus !== 'ywc'
}
function hasMoreActions(row: ProductionWorkOrderItem) {
return canDispatchTask(row) || canDeleteWorkOrder(row) || true
}
</script>
<style scoped lang="scss">
.production-work-order-cards-body {
border-top: 1px solid var(--mint-border, #e2e8f0);
}
.production-work-order-cards-wrap {
display: flex;
flex-direction: column;
gap: 14px;
min-height: 120px;
padding: 16px;
}
.production-work-order-card {
display: flex;
flex-direction: column;
min-width: 0;
border: 1px solid #e2e8f0;
border-radius: 10px;
background: #fff;
overflow: hidden;
transition:
border-color 0.15s ease,
box-shadow 0.15s ease;
&:hover {
border-color: #a7f3d0;
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
}
}
.production-work-order-card__head {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 10px;
padding: 14px 16px;
border-bottom: 1px solid #e2e8f0;
background: #fafafa;
}
.production-work-order-card__head-main {
min-width: 0;
}
.production-work-order-card__title-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.production-work-order-card__checkbox {
flex-shrink: 0;
margin-right: -4px;
}
.production-work-order-card__index {
flex-shrink: 0;
font-size: 12px;
color: #94a3b8;
min-width: 20px;
}
.production-work-order-card__no {
font-size: 15px;
font-weight: 600;
color: #1e293b;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
word-break: break-all;
}
.production-work-order-card__meta {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 8px 12px;
margin: 0;
}
.production-work-order-card__meta-item {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
dt {
margin: 0;
font-size: 11px;
line-height: 1.35;
color: #94a3b8;
}
dd {
margin: 0;
font-size: 13px;
line-height: 1.4;
color: #334155;
word-break: break-word;
}
&--wide {
grid-column: 1 / -1;
}
}
.production-work-order-card__ops {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
flex-shrink: 0;
}
.production-work-order-card__tasks {
background: #fafafa;
}
.production-work-order-cards-empty {
padding: 24px 0;
}
</style>
@@ -1,121 +1,134 @@
<!-- 生产工单展开行 · 生产任务子列表 -->
<!-- 生产工单 · 生产任务子列表 -->
<template>
<div class="work-order-task-sublist">
<div class="work-order-task-sublist" :class="{ 'work-order-task-sublist--embedded': embedded }">
<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 v-if="tableData.length" class="work-order-task-cards-area">
<div class="work-order-task-sublist__head">
<div class="work-order-task-sublist__head-title">生产任务</div>
<div class="work-order-task-sublist__head-extra">
<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
v-if="!embedded"
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>
<div
v-for="(row, idx) in tableData"
:key="row.id || idx"
class="work-order-task-card"
@dblclick="handleViewDetail(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>
<el-tag
v-if="productionConclusionTagType(row.conclusion)"
:type="productionConclusionTagType(row.conclusion)"
size="small"
>
{{ row.conclusionLabel || productionConclusionLabel(row.conclusion) }}
</el-tag>
</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>
<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 class="work-order-task-cards-grid">
<div
v-for="(row, idx) in tableData"
:key="row.id || idx"
class="work-order-task-card"
@dblclick="handleViewDetail(row)"
>
<div class="work-order-task-card__line work-order-task-card__line--top">
<span class="work-order-task-card__name">{{ row.taskName || row.taskNo || '—' }}</span>
<div class="work-order-task-card__tags">
<el-tag :type="taskStatusTag(row.taskStatus).type" size="small">
{{ taskStatusTag(row.taskStatus).label }}
</el-tag>
<el-tag
v-if="productionConclusionTagType(row.conclusion)"
:type="productionConclusionTagType(row.conclusion)"
size="small"
>
{{ row.conclusionLabel || productionConclusionLabel(row.conclusion) }}
</el-tag>
</div>
</div>
<div class="work-order-task-card__line work-order-task-card__line--bottom">
<span class="work-order-task-card__code">{{ row.taskNo || '—' }}</span>
<span class="work-order-task-card__sep">·</span>
<el-tag :type="productionTaskTypeTag(row.taskType, row.orderSource).type" size="small">
{{ productionTaskTypeTag(row.taskType, row.orderSource).label }}
</el-tag>
<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>
<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>
</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 v-else-if="!loading" class="work-order-task-cards-area work-order-task-cards-area--empty">
<div class="work-order-task-sublist__head">
<div class="work-order-task-sublist__head-title">生产任务</div>
<div class="work-order-task-sublist__head-extra">
<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
v-if="!embedded"
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>
<el-empty
class="work-order-task-sublist__empty"
@@ -183,6 +196,8 @@
workOrder: Record<string, any>
/** 父级派发/完成工单后递增,用于刷新已展开子列表 */
refreshToken?: number
/** 内嵌于工单卡片时收紧布局并隐藏子列表派发按钮 */
embedded?: boolean
}>()
const emit = defineEmits<{
@@ -320,27 +335,65 @@
padding: 8px 12px 10px 40px;
background: #f8fafc;
text-align: left;
&--embedded {
padding: 10px 14px 12px;
background: transparent;
}
}
.work-order-task-sublist__panel {
min-height: 32px;
}
.work-order-task-cards-wrap {
.work-order-task-cards-area {
display: flex;
flex-direction: column;
gap: 10px;
&--empty {
gap: 4px;
}
}
.work-order-task-sublist__head {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.work-order-task-sublist__summary {
flex: 0 0 auto;
.work-order-task-sublist__head-title {
font-size: 12px;
font-weight: 600;
color: #64748b;
letter-spacing: 0.02em;
}
.work-order-task-sublist__head-extra {
display: inline-flex;
align-items: center;
flex-wrap: wrap;
gap: 4px 8px;
padding-top: 8px;
min-height: 34px;
}
.work-order-task-cards-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
@media (max-width: 1200px) {
.work-order-task-cards-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.work-order-task-cards-grid {
grid-template-columns: 1fr;
}
}
.work-order-task-sublist__count {
@@ -365,18 +418,7 @@
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) {
@@ -388,9 +430,7 @@
display: flex;
flex-direction: column;
gap: 6px;
flex: 0 0 248px;
width: 248px;
max-width: 248px;
min-width: 0;
padding: 8px 10px;
border: 1px solid #e2e8f0;
border-radius: 8px;
@@ -404,12 +444,22 @@
}
}
.work-order-task-card__head {
.work-order-task-card__line {
display: flex;
align-items: flex-start;
justify-content: space-between;
align-items: center;
gap: 6px;
min-width: 0;
&--top {
flex-wrap: wrap;
row-gap: 4px;
justify-content: space-between;
}
&--bottom {
flex-wrap: wrap;
row-gap: 4px;
}
}
.work-order-task-card__name {
@@ -420,18 +470,18 @@
color: #1e293b;
line-height: 1.35;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
word-break: break-word;
}
.work-order-task-card__meta {
display: flex;
.work-order-task-card__tags {
display: inline-flex;
flex-wrap: wrap;
align-items: center;
gap: 4px 6px;
min-width: 0;
gap: 4px;
flex-shrink: 0;
}
.work-order-task-card__code {
@@ -439,17 +489,20 @@
font-size: 11px;
color: #475569;
line-height: 1.35;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 0;
}
.work-order-task-card__sep {
flex-shrink: 0;
color: #cbd5e1;
font-size: 11px;
}
.work-order-task-sublist__ops {
display: flex;
display: inline-flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
padding-top: 2px;
gap: 4px;
margin-left: auto;
}
</style>
@@ -93,270 +93,26 @@
</div>
</div>
<div class="list-body list-wrap">
<el-table
ref="workOrderListTableRef"
class="production-work-order-table list-table"
:data="tableData"
v-loading="loading"
stripe
row-key="id"
@selection-change="handleSelectionChange"
@expand-change="handleWorkOrderRowExpand"
>
<el-table-column type="selection" min-width="55" align="center" header-align="center" />
<el-table-column type="expand" min-width="64">
<template #default="{ row }">
<WorkOrderTaskSubList
:work-order="row"
:refresh-token="taskSubListRefreshToken"
@changed="handleWorkOrderTasksChanged"
/>
</template>
</el-table-column>
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
:index="(i) => (pagination.page - 1) * pagination.pageSize + i + 1"
/>
<el-table-column prop="workOrderNo" label="工单号" min-width="150" align="center" />
<el-table-column
v-if="activeTypeTab === 'outbound'"
prop="workOrderStatus"
label="工单状态"
min-width="100"
align="center"
>
<template #default="{ row }">
<el-tag :type="woStatusTag(row.workOrderStatus).type" size="small">
{{ woStatusTag(row.workOrderStatus).label }}
</el-tag>
</template>
</el-table-column>
<!-- 出库工单专属列 -->
<el-table-column
v-if="activeTypeTab === 'outbound'"
prop="bizTypeLabel"
label="业务类型"
min-width="110"
align="center"
>
<template #default="{ row }">
<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
v-if="activeTypeTab === 'outbound'"
prop="applicationNo"
label="申请单号"
min-width="150"
align="center"
>
<template #default="{ row }">{{ row.applicationNo || '—' }}</template>
</el-table-column>
<el-table-column
v-if="activeTypeTab === 'outbound'"
prop="patientName"
label="用户名称"
min-width="100"
align="center"
>
<template #default="{ row }">{{ row.patientName || '—' }}</template>
</el-table-column>
<el-table-column
v-if="activeTypeTab === 'outbound'"
label="第几次"
min-width="88"
align="center"
>
<template #default="{ row }">{{ formatOutboundScheduleSortNo(row) }}</template>
</el-table-column>
<el-table-column
v-if="activeTypeTab === 'outbound'"
label="总次数"
min-width="88"
align="center"
>
<template #default="{ row }">{{ formatOutboundScheduleTotalCount(row) }}</template>
</el-table-column>
<el-table-column
v-if="activeTypeTab === 'outbound'"
prop="infusionTime"
label="输注时间"
min-width="170"
align="center"
>
<template #default="{ row }">{{ row.infusionTime || '—' }}</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="protocolStatus"
label="协议状态"
min-width="100"
align="center"
>
<template #default="{ row }">
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
<el-tag
v-else
:type="
protocolStatusTagTypeBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
"
size="small"
>{{
protocolStatusLabelBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
}}</el-tag
>
</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="sampleCode"
label="样本编码"
min-width="120"
align="center"
>
<template #default="{ row }">{{ formatTempEmptyField(row, row.sampleCode) }}</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="labStorageCode"
label="实验室入库编码"
min-width="150"
align="center"
>
<template #default="{ row }">{{
formatTempEmptyField(row, row.labStorageCode)
}}</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="receptionSource"
label="来源类型"
min-width="110"
align="center"
>
<template #default="{ row }">
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
<el-tag v-else :type="sourceTag(row.receptionSource).type" size="small">
{{ row.receptionSourceLabel || sourceTag(row.receptionSource).label }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="sampleTypeName"
label="样本类型"
min-width="110"
align="center"
>
<template #default="{ row }">{{ row.sampleTypeName || '—' }}</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="handlerName"
label="接收人"
min-width="100"
align="center"
>
<template #default="{ row }">{{ row.handlerName || '—' }}</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
label="是否超24小时"
min-width="120"
align="center"
>
<template #default="{ row }">
<span v-if="!row.receptionTime">—</span>
<el-tag v-else :type="receptionOver24HoursTag(row.receptionTime).type" size="small">
{{ receptionOver24HoursTag(row.receptionTime).label }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="showReceptionCols"
prop="receptionTime"
label="接收时间"
min-width="170"
align="center"
>
<template #default="{ row }">{{ row.receptionTime || '—' }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="140" align="center">
<template #default="{ row }">{{ row.remark || '—' }}</template>
</el-table-column>
<el-table-column
v-if="activeTypeTab !== 'outbound'"
prop="workOrderStatus"
label="工单状态"
min-width="100"
align="center"
>
<template #default="{ row }">
<el-tag :type="woStatusTag(row.workOrderStatus).type" size="small">
{{ woStatusTag(row.workOrderStatus).label }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" min-width="170" align="center" />
<el-table-column
label="操作"
min-width="160"
fixed="right"
align="center"
header-align="center"
>
<template #default="{ row }">
<div style="display: flex; justify-content: center; gap: 8px">
<el-button class="btn-op-item primary" @click="handleView(row)">
<el-icon><View /></el-icon>查看
</el-button>
<el-dropdown 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 command="edit">
<el-icon><EditPen /></el-icon>编辑
</el-dropdown-item>
<el-dropdown-item v-if="canDeleteWorkOrder(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>
<div class="pagination list-pager-bar">
<el-pagination
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
layout="total, sizes, prev, pager, next"
@size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
@current-change="(v) => ((pagination.page = v), loadData())"
/>
</div>
</div>
<ProductionWorkOrderCardList
:rows="tableData"
:loading="loading"
:active-type-tab="activeTypeTab"
:page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
:task-refresh-token="taskSubListRefreshToken"
:selected-ids="selectedIds"
@view="handleView"
@dispatch="handleOpenDispatch"
@dispatch-qc="handleOpenDispatchQc"
@complete="handleCompleteSingle"
@command="handleDropdownCommand"
@toggle-select="handleCardToggleSelect"
@tasks-changed="handleWorkOrderTasksChanged"
@page-change="(v) => ((pagination.page = v), loadData())"
@page-size-change="(v) => ((pagination.page = 1), (pagination.pageSize = v), loadData())"
/>
<!-- 查看详情弹窗 -->
<SystemViewDialog
@@ -448,6 +204,12 @@
@success="handleDispatchSuccess"
/>
<DispatchQcWorkOrderDialog
v-model:visible="dispatchQcVisible"
:work-order-row="dispatchQcRow"
@success="handleDispatchQcSuccess"
/>
<!-- 新增生产工单弹窗 -->
<el-dialog
v-model="addVisible"
@@ -520,8 +282,8 @@
</template>
<script setup lang="ts">
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
import type { TableInstance } from 'element-plus'
import { ref, reactive, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Plus,
@@ -531,10 +293,7 @@
RefreshLeft,
View,
Document,
Position,
EditPen,
Delete,
More
Position
} from '@element-plus/icons-vue'
import {
fetchProductionWorkOrderList,
@@ -543,7 +302,8 @@
fetchCreateProductionWorkOrder,
fetchUpdateProductionWorkOrder,
fetchDeleteProductionWorkOrder,
type ProductionWorkOrderDetail
type ProductionWorkOrderDetail,
type ProductionWorkOrderItem
} from '@/api/production-work-order'
import {
receptionSourceLabel,
@@ -628,16 +388,16 @@
import type { ViewSection } from '@/components/business/system-view-dialog/index.vue'
import { downloadAttachmentFile } from '@/utils/download-attachment'
import DispatchTaskDialog from './DispatchTaskDialog.vue'
import DispatchQcWorkOrderDialog from './DispatchQcWorkOrderDialog.vue'
import ProductionWorkOrderCardList from './ProductionWorkOrderCardList.vue'
import WorkOrderRemarkDialog from '@/components/business/work-order-remark-dialog/index.vue'
import WorkOrderTaskSubList from './WorkOrderTaskSubList.vue'
defineOptions({ name: 'ProductionProductionWorkOrder' })
const router = useRouter()
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound'
const activeTypeTab = ref<WorkOrderTypeTab>('inbound')
const showReceptionCols = computed(
() => activeTypeTab.value !== 'temporary' && activeTypeTab.value !== 'outbound'
)
const searchPlaceholder = computed(() => {
if (activeTypeTab.value === 'temporary') return '工单号'
if (activeTypeTab.value === 'outbound') return '工单号/申请单号'
@@ -774,9 +534,9 @@
const searchForm = reactive({ keyword: '', workOrderStatus: '' })
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
const tableData = ref<any[]>([])
const selectedRows = ref<any[]>([])
const workOrderListTableRef = ref<TableInstance>()
const tableData = ref<ProductionWorkOrderItem[]>([])
const selectedRows = ref<ProductionWorkOrderItem[]>([])
const selectedIds = computed(() => selectedRows.value.map((r) => r.id))
const loading = ref(false)
const pagination = reactive({ page: 1, pageSize: 10, total: 0 })
const taskSubListRefreshToken = ref(0)
@@ -794,13 +554,18 @@
)
})
function handleSelectionChange(rows: any[]) {
selectedRows.value = rows
function handleCardToggleSelect(row: ProductionWorkOrderItem, checked: boolean) {
if (checked) {
if (!selectedRows.value.some((r) => r.id === row.id)) {
selectedRows.value = [...selectedRows.value, row]
}
} else {
selectedRows.value = selectedRows.value.filter((r) => r.id !== row.id)
}
}
function clearSelection() {
selectedRows.value = []
workOrderListTableRef.value?.clearSelection?.()
}
function requireSingleSelection(action: string) {
@@ -843,19 +608,9 @@
await loadData()
}
async function layoutWorkOrderTable() {
await nextTick()
workOrderListTableRef.value?.doLayout?.()
}
async function handleWorkOrderRowExpand(_row: any, _expandedRows: any[]) {
await layoutWorkOrderTable()
}
async function handleWorkOrderTasksChanged() {
taskSubListRefreshToken.value += 1
await loadData()
await layoutWorkOrderTable()
}
async function handleDispatchSuccess() {
@@ -892,9 +647,11 @@
})
tableData.value = res.list || []
pagination.total = res.total ?? 0
selectedRows.value = selectedRows.value.filter((row) =>
tableData.value.some((item) => item.id === row.id)
)
} finally {
loading.value = false
await layoutWorkOrderTable()
}
}
function handleSearch() {
@@ -1136,12 +893,53 @@
// ── 派发任务 ──────────────────────────────────────────
const dispatchVisible = ref(false)
const dispatchRow = ref<any>(null)
function handleOpenDispatch(row: any) {
const dispatchRow = ref<ProductionWorkOrderItem | null>(null)
function handleOpenDispatch(row: ProductionWorkOrderItem) {
dispatchRow.value = row
dispatchVisible.value = true
}
const dispatchQcVisible = ref(false)
const dispatchQcRow = ref<ProductionWorkOrderItem | null>(null)
function handleOpenDispatchQc(row: ProductionWorkOrderItem) {
dispatchQcRow.value = row
dispatchQcVisible.value = true
}
function handleDispatchQcSuccess(payload: { sampleCode?: string }) {
taskSubListRefreshToken.value += 1
loadData()
if (payload.sampleCode) {
ElMessageBox.confirm('是否前往质检工单列表查看?', '提示', {
type: 'info',
confirmButtonText: '前往',
cancelButtonText: '留在此页'
})
.then(() => {
router.push({
path: '/quality-manage/qc-work-order',
query: { sampleCode: payload.sampleCode }
})
})
.catch(() => {})
}
}
async function handleCompleteSingle(row: ProductionWorkOrderItem) {
if (row.workOrderStatus !== 'dpz' && row.workOrderStatus !== 'jxz') {
ElMessage.warning('仅待配置或进行中的工单可完成')
return
}
await ElMessageBox.confirm(`确定要完成工单「${row.workOrderNo || ''}」吗?`, '提示', {
type: 'warning'
})
await fetchCompleteProductionWorkOrder(row.id, {})
ElMessage.success('工单已完成')
selectedRows.value = selectedRows.value.filter((r) => r.id !== row.id)
taskSubListRefreshToken.value += 1
await loadData()
}
// 输入检索条件时自动搜索(防抖 300ms)
watchDebounced(
[searchForm, createTimeRange],
@@ -1158,44 +956,6 @@
</script>
<style scoped lang="scss">
.production-work-order-table :deep(td.el-table__expanded-cell) {
padding: 0 !important;
text-align: left !important;
}
.production-work-order-table :deep(td.el-table__expanded-cell > .cell) {
display: block !important;
padding: 0 !important;
text-align: left !important;
}
.production-work-order-table :deep(.el-table__expand-icon) {
width: 28px;
height: 28px;
border-radius: 6px;
border: 1px solid var(--mint-border, #d9e8e2);
display: inline-flex;
align-items: center;
justify-content: center;
transition:
background 0.15s ease,
border-color 0.15s ease;
color: var(--mint-text-muted, #64748b);
background: var(--mint-surface, #fff);
}
.production-work-order-table :deep(.el-table__expand-icon:hover) {
background: var(--mint-primary-bg, #ecfdf5);
border-color: #10b981;
color: var(--mint-primary-dark, #059669);
}
.production-work-order-table :deep(.el-table__expand-icon--expanded) {
background: var(--mint-primary-bg, #ecfdf5);
border-color: #10b981;
color: var(--mint-primary-dark, #059669);
}
.work-order-type-tabs {
padding: 0 16px;
margin-bottom: 4px;
@@ -145,7 +145,8 @@
bizTypeLabel,
bizTypeTagType,
productStatusLabel,
productStatusTagType
productStatusTagType,
payStatusTagType
} from '@/utils/status-tag-registry'
import {
buildOutboundPilotContextSections,
@@ -155,6 +156,7 @@
import type { ViewField, ViewSection } from '@/components/business/system-view-dialog/index.vue'
import ProtocolAttachmentReadonly from '@/views/cell-storage/protocol/ProtocolAttachmentReadonly.vue'
import { downloadAttachmentFile } from '@/utils/download-attachment'
import { formatMoneyDisplay } from '@/utils/money-format'
defineOptions({ name: 'OutboundQcViewDialog' })
@@ -475,6 +477,43 @@
const variant = resolveOutboundViewVariant(d.application?.bizType || d.workOrder?.bizType)
result.push(...buildOutboundPilotContextSections(d, variant))
const feeSummary = d.feeSummary || d.workOrder?.feeSummary
if (variant === 'basic_experiment') {
result.push({
title: '缴费信息',
fields: feeSummary
? [
{
label: '售卖金额(元)',
value:
feeSummary.saleAmount != null
? formatMoneyDisplay(feeSummary.saleAmount)
: '—'
},
{
label: '应缴金额(元)',
value:
feeSummary.paymentAmount != null
? formatMoneyDisplay(feeSummary.paymentAmount)
: '—'
},
{
label: '实收金额(元)',
value:
feeSummary.transferAmount != null
? formatMoneyDisplay(feeSummary.transferAmount)
: '—'
},
{
label: '缴费状态',
value: feeSummary.payStatusLabel || '—',
tagType: payStatusTagType(feeSummary.payStatus || '') as ViewField['tagType']
}
]
: [{ label: '缴费信息', value: '暂无缴费记录', span: true }]
})
}
// 检测结果 — lab tasks
const labSections = buildTaskTypeSections(tasksWithResults.value, 'sysz', '实验室项目')
result.push(...labSections)
@@ -1,218 +1,36 @@
<!-- 质检工单 · 卡片列表(工单大卡片 + 任务小卡片) -->
<!-- 质检工单 · 卡片列表(入库按样本分组 + 出库/临时单列) -->
<template>
<div class="list-body list-wrap qc-work-order-cards-body">
<div v-loading="loading" class="qc-work-order-cards-wrap">
<article v-for="(row, idx) in rows" :key="row.id" class="qc-work-order-card">
<header class="qc-work-order-card__head">
<div class="qc-work-order-card__head-main">
<div class="qc-work-order-card__title-row">
<span class="qc-work-order-card__index">{{ cardIndex(idx) }}</span>
<span class="qc-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
<el-tag :type="workOrderStatusTagType(row.workOrderStatus)" size="small">
{{ workOrderStatusLabel(row.workOrderStatus) }}
</el-tag>
</div>
<dl class="qc-work-order-card__meta">
<template v-if="activeTypeTab === 'outbound'">
<div class="qc-work-order-card__meta-item">
<dt>业务类型</dt>
<dd>
<el-tag
:type="
row.bizType === 'pilot_service'
? 'primary'
: row.bizType === 'clinical_application'
? 'warning'
: 'info'
"
size="small"
>
{{ row.bizTypeLabel || '—' }}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>申请单号</dt>
<dd>{{ row.applicationNo || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>用户名称</dt>
<dd>{{ row.patientName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>第几次</dt>
<dd>{{ formatOutboundScheduleSortNo(row) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>总次数</dt>
<dd>{{ formatOutboundScheduleTotalCount(row) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>申请单名称</dt>
<dd>{{ row.applicationName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>渠道名称</dt>
<dd>{{ row.channelName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>输注时间</dt>
<dd>{{ row.infusionTime || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>来源类型</dt>
<dd>
<el-tag
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
size="small"
>
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
</el-tag>
</dd>
</div>
</template>
<template v-else-if="activeTypeTab === 'temporary'">
<div class="qc-work-order-card__meta-item">
<dt>业务类型</dt>
<dd>
<el-tag :type="qcBizTypeTagType('temporary')" size="small">
{{ row.qcBizTypeLabel || qcBizTypeLabel('temporary') }}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>产品编码</dt>
<dd>{{ formatTempCellProductField(row, row.cellProductCode) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>产品名称</dt>
<dd>{{ formatTempCellProductField(row, row.cellProductName) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>产品类型</dt>
<dd>{{ formatTempCellProductField(row, row.cellProductTypeName) }}</dd>
</div>
</template>
<template v-else>
<div class="qc-work-order-card__meta-item">
<dt>样本编码</dt>
<dd>{{ formatTempEmptyField(row, row.sampleCode) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>实验室入库编码</dt>
<dd>{{ formatTempEmptyField(row, row.labStorageCode) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>来源类型</dt>
<dd>
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
<el-tag
v-else
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
size="small"
>
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>协议状态</dt>
<dd>
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
<el-tag
v-else
:type="
protocolStatusTagTypeBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
"
size="small"
>
{{
protocolStatusLabelBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
}}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>样本类型</dt>
<dd>{{ row.sampleTypeName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>接收时间</dt>
<dd>{{ row.receptionTime || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>接收经手人</dt>
<dd>{{ row.handlerName || '—' }}</dd>
</div>
</template>
<div class="qc-work-order-card__meta-item">
<dt>检测方式</dt>
<dd>{{ formatDetectMethods(row) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>{{ activeTypeTab === 'outbound' ? '创建时间' : '创建时间' }}</dt>
<dd>{{ row.createTime || '—' }}</dd>
</div>
<div v-if="row.remark" class="qc-work-order-card__meta-item qc-work-order-card__meta-item--wide">
<dt>备注</dt>
<dd>{{ row.remark }}</dd>
</div>
</dl>
</div>
<div v-if="activeTypeTab !== 'all'" class="qc-work-order-card__ops">
<el-button
v-if="canConfigureWorkOrder(row)"
class="btn-op-item primary"
type="primary"
@click="emit('configure', row)"
>
<el-icon><Setting /></el-icon
>{{ row.workOrderStatus !== 'dpz' ? '调整检测' : '配置检测' }}
</el-button>
<el-button v-else class="btn-op-item primary" @click="emit('view', row)">
<el-icon><View /></el-icon>查看
</el-button>
<el-dropdown
v-if="hasMoreWorkOrderActions(row)"
trigger="hover"
@command="(cmd) => emit('command', 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="canConfigureWorkOrder(row)" command="view">
<el-icon><View /></el-icon>查看
</el-dropdown-item>
<el-dropdown-item
v-if="canEditTemporaryWorkOrder(row) || canEditRemarkWorkOrder(row)"
command="edit"
>
<el-icon><EditPen /></el-icon>编辑
</el-dropdown-item>
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
<el-icon><Delete /></el-icon>删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</header>
<section v-if="activeTypeTab !== 'all'" class="qc-work-order-card__tasks">
<QcWorkOrderTaskSubList
:work-order="row"
:refresh-token="taskRefreshToken"
@changed="emit('tasks-changed')"
/>
</section>
</article>
<template v-if="activeTypeTab === 'inbound'">
<QcWorkOrderSampleGroup
v-for="(group, idx) in inboundGroups"
:key="group.groupKey"
:group="group"
:group-index="cardIndex(idx)"
active-type-tab="inbound"
:task-refresh-token="taskRefreshToken"
@configure="(row) => emit('configure', row)"
@view="(row) => emit('view', row)"
@command="(cmd, row) => emit('command', cmd, row)"
@tasks-changed="emit('tasks-changed')"
/>
</template>
<template v-else>
<QcWorkOrderSingleCard
v-for="(row, idx) in rows"
:key="row.id"
layout="standalone"
:row="row"
:active-type-tab="activeTypeTab"
:card-index="cardIndex(idx)"
:task-refresh-token="taskRefreshToken"
@configure="(row) => emit('configure', row)"
@view="(row) => emit('view', row)"
@command="(cmd, row) => emit('command', cmd, row)"
@tasks-changed="emit('tasks-changed')"
/>
</template>
<el-empty
v-if="!loading && !rows.length"
class="qc-work-order-cards-empty"
@@ -234,22 +52,11 @@
</template>
<script setup lang="ts">
import { Setting, View, More, EditPen, Delete } from '@element-plus/icons-vue'
import { computed } from 'vue'
import type { QcWorkOrder } from '@/api/qc-work-order'
import {
workOrderStatusLabel,
receptionSourceLabel,
qcBizTypeLabel
} from '@/utils/qc-labels'
import {
protocolStatusLabel,
protocolStatusTagType,
donationStatusLabel,
donationStatusTagType,
qcBizTypeTagType
} from '@/utils/status-tag-registry'
import type { TagType } from '@/utils/status-tag-registry'
import QcWorkOrderTaskSubList from './QcWorkOrderTaskSubList.vue'
import { groupInboundQcWorkOrders } from '@/utils/qc-work-order-groups'
import QcWorkOrderSampleGroup from './QcWorkOrderSampleGroup.vue'
import QcWorkOrderSingleCard from './QcWorkOrderSingleCard.vue'
defineOptions({ name: 'QcWorkOrderCardList' })
@@ -274,97 +81,13 @@
'page-size-change': [size: number]
}>()
function protocolStatusLabelBySource(status: string, source: string): string {
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
}
function protocolStatusTagTypeBySource(status: string, source: string): TagType {
return source === 'research_donation' ? donationStatusTagType(status) : protocolStatusTagType(status)
}
function shouldShowTempEmptyField(row: QcWorkOrder, value?: string | null) {
return row.workOrderType === 'temporary' && !String(value || '').trim()
}
function formatTempEmptyField(row: QcWorkOrder, value?: string | null) {
return shouldShowTempEmptyField(row, value) ? '—' : String(value || '')
}
function formatTempCellProductField(row: QcWorkOrder, value?: string | null) {
if (row.workOrderType !== 'temporary') return '—'
return String(value || '').trim() || '—'
}
function formatOutboundScheduleSortNo(row: Record<string, unknown>) {
const n = row.sortNo ?? row.orderNum
if (n == null || n === '' || Number(n) <= 0) return '—'
return `第${Number(n)}次`
}
function formatOutboundScheduleTotalCount(row: Record<string, unknown>) {
const n = row.totalCourseCount
if (n == null || n === '' || Number(n) <= 0) return '—'
return `共${Number(n)}次`
}
function formatDetectMethods(row: QcWorkOrder) {
const parts: string[] = []
if (row.hasLab) parts.push('实验室')
if (row.hasThirdParty) parts.push('第三方')
return parts.length ? parts.join(' / ') : '—'
}
function workOrderStatusTagType(status: string): TagType {
if (status === 'ywc') return 'success'
if (status === 'ypz') return 'warning'
if (status === 'yzf') return 'danger'
return 'info'
}
const inboundGroups = computed(() =>
props.activeTypeTab === 'inbound' ? groupInboundQcWorkOrders(props.rows) : []
)
function cardIndex(i: number) {
return (props.page - 1) * props.pageSize + i + 1
}
function canConfigureWorkOrder(_row: QcWorkOrder) {
return true
}
function canEditTemporaryWorkOrder(row: QcWorkOrder) {
return (
props.activeTypeTab === 'temporary' ||
(props.activeTypeTab === 'all' && row.workOrderType === 'temporary')
)
}
function canEditRemarkWorkOrder(row: QcWorkOrder) {
if (props.activeTypeTab === 'inbound') return true
if (props.activeTypeTab === 'all' && row.workOrderType !== 'temporary') return true
if (
props.activeTypeTab === 'outbound' &&
row.workOrderStatus !== 'ywc' &&
row.workOrderStatus !== 'yzf'
) {
return true
}
return false
}
function canDeleteWorkOrder(row: QcWorkOrder) {
return (
props.activeTypeTab !== 'outbound' &&
props.activeTypeTab !== 'all' &&
row.workOrderStatus !== 'ywc'
)
}
function hasMoreWorkOrderActions(row: QcWorkOrder) {
if (canConfigureWorkOrder(row)) return true
return (
canEditTemporaryWorkOrder(row) ||
canEditRemarkWorkOrder(row) ||
canDeleteWorkOrder(row)
)
}
</script>
<style scoped lang="scss">
@@ -373,163 +96,14 @@
}
.qc-work-order-cards-wrap {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(480px, 1fr));
display: flex;
flex-direction: column;
gap: 14px;
min-height: 120px;
padding: 16px;
}
.qc-work-order-card {
display: flex;
flex-direction: column;
height: 100%;
min-width: 0;
border: 1px solid #e2e8f0;
border-radius: 10px;
background: #fff;
overflow: hidden;
transition:
border-color 0.15s ease,
box-shadow 0.15s ease;
&:hover {
border-color: #a7f3d0;
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
}
}
.qc-work-order-card__head {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 10px;
padding: 14px 16px;
border-bottom: 1px solid #e2e8f0;
background: #fafafa;
}
.qc-work-order-card__head-main {
min-width: 0;
}
.qc-work-order-card__title-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.qc-work-order-card__index {
flex-shrink: 0;
font-size: 12px;
color: #94a3b8;
min-width: 20px;
}
.qc-work-order-card__no {
font-size: 15px;
font-weight: 600;
color: #1e293b;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
word-break: break-all;
}
.qc-work-order-card__meta {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 8px 12px;
margin: 0;
}
.qc-work-order-card__meta-item {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
dt {
margin: 0;
font-size: 11px;
line-height: 1.35;
color: #94a3b8;
}
dd {
margin: 0;
font-size: 13px;
line-height: 1.4;
color: #334155;
word-break: break-word;
}
&--wide {
grid-column: 1 / -1;
}
}
.qc-work-order-card__ops {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
flex-shrink: 0;
}
.qc-work-order-card__tasks {
display: flex;
flex-direction: column;
flex: 0 1 auto;
padding: 12px 16px 14px;
background: #f8fafc;
}
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) {
flex: 1 1 auto;
min-height: 232px;
}
.qc-work-order-cards-empty {
grid-column: 1 / -1;
padding: 24px 0;
}
.qc-work-order-card__tasks :deep(.qc-work-order-task-sublist) {
padding: 0;
background: transparent;
}
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-work-order-task-sublist) {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-work-order-task-sublist__panel) {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-task-cards-wrap--empty) {
flex: 1;
min-height: 204px;
}
.qc-work-order-card__tasks:has(.qc-task-cards-wrap--empty) :deep(.qc-work-order-task-sublist__empty) {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0;
}
.qc-work-order-card__tasks :deep(.qc-task-cards-wrap:not(.qc-task-cards-wrap--empty)) {
padding: 0;
}
</style>
@@ -0,0 +1,139 @@
<!-- 质检工单 · 用户费用摘要条(采集协议 / 基础实验) -->
<template>
<div v-if="visible" class="qc-fee-summary">
<span class="qc-fee-summary__label">{{ label }}</span>
<template v-if="variant === 'protocol' && paymentSummary">
<span v-if="paymentSummary.payModeLabel" class="qc-fee-summary__item">
{{ paymentSummary.payModeLabel }}
</span>
<span class="qc-fee-summary__item">
合同 {{ formatAmount(paymentSummary.contractAmount) }}
</span>
<span class="qc-fee-summary__item">
已收 {{ formatAmount(paymentSummary.receivedAmount) }}
</span>
<span class="qc-fee-summary__item">
待收 {{ formatAmount(paymentSummary.pendingAmount) }}
</span>
<span v-if="paymentSummary.statusHint" class="qc-fee-summary__hint">
{{ paymentSummary.statusHint }}
</span>
<el-tag
v-if="paymentSummary.overallPayStatusLabel"
:type="protocolTagType"
size="small"
class="qc-fee-summary__tag"
>
{{ paymentSummary.overallPayStatusLabel }}
</el-tag>
</template>
<template v-else-if="variant === 'protocol'">
<span class="qc-fee-summary__empty">暂无缴费信息</span>
</template>
<template v-else-if="variant === 'basic-experiment'">
<span class="qc-fee-summary__item">
售卖 {{ formatAmount(feeSummary?.saleAmount) }}
</span>
<template v-if="feeSummary?.paymentAmount != null">
<span class="qc-fee-summary__item">
应缴 {{ formatAmount(feeSummary.paymentAmount) }}
</span>
<span
v-if="feeSummary.transferAmount != null"
class="qc-fee-summary__item"
>
实收 {{ formatAmount(feeSummary.transferAmount) }}
</span>
<el-tag
v-if="feeSummary.payStatusLabel"
:type="basicPayTagType"
size="small"
class="qc-fee-summary__tag"
>
{{ feeSummary.payStatusLabel }}
</el-tag>
</template>
<span v-else class="qc-fee-summary__empty">暂无缴费记录</span>
</template>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type {
QcBasicExperimentFeeSummary,
QcProtocolPaymentSummary
} from '@/api/qc-work-order'
import { formatMoneyDisplay } from '@/utils/money-format'
import { payStatusTagType } from '@/utils/status-tag-registry'
import type { TagType } from '@/utils/status-tag-registry'
defineOptions({ name: 'QcWorkOrderFeeSummaryBar' })
const props = defineProps<{
variant: 'protocol' | 'basic-experiment'
paymentSummary?: QcProtocolPaymentSummary | null
feeSummary?: QcBasicExperimentFeeSummary | null
visible?: boolean
}>()
const visible = computed(() => props.visible !== false)
const label = computed(() =>
props.variant === 'protocol' ? '协议费用' : '费用信息'
)
const protocolTagType = computed((): TagType => {
const t = props.paymentSummary?.overallPayStatusTagType
if (t === 'success' || t === 'warning' || t === 'danger' || t === 'info') {
return t
}
return 'info'
})
const basicPayTagType = computed((): TagType =>
payStatusTagType(props.feeSummary?.payStatus || '')
)
function formatAmount(val?: number | null) {
if (val == null || Number.isNaN(Number(val))) return '—'
return `¥${formatMoneyDisplay(val)}`
}
</script>
<style scoped lang="scss">
.qc-fee-summary {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px 12px;
padding: 10px 16px;
background: #ecfdf5;
border-bottom: 1px solid #d1fae5;
font-size: 12px;
line-height: 1.4;
}
.qc-fee-summary__label {
flex-shrink: 0;
font-weight: 600;
color: #059669;
}
.qc-fee-summary__item {
color: #334155;
font-weight: 500;
}
.qc-fee-summary__hint {
color: #64748b;
}
.qc-fee-summary__empty {
color: #94a3b8;
}
.qc-fee-summary__tag {
margin-left: auto;
}
</style>
@@ -0,0 +1,198 @@
<!-- 质检工单 · 采集协议缴费(汇总 + 分期明细表) -->
<template>
<section class="qc-protocol-payment" :class="{ 'qc-protocol-payment--embedded': embedded }">
<div v-if="summary" class="qc-protocol-payment__head">
<span v-if="!embedded" class="qc-protocol-payment__title">协议费用</span>
<el-tag v-if="summary?.payModeLabel" :type="payModeTagType" size="small">
{{ summary.payModeLabel }}
</el-tag>
<el-tag
v-if="summary?.overallPayStatusLabel"
:type="overallStatusTagType"
size="small"
>
{{ summary.overallPayStatusLabel }}
</el-tag>
</div>
<template v-if="summary">
<div class="qc-protocol-payment__metrics">
<div class="qc-protocol-payment__metric">
<span class="qc-protocol-payment__metric-label">合同金额</span>
<span class="qc-protocol-payment__metric-value">{{
formatAmount(summary.contractAmount)
}}</span>
</div>
<div class="qc-protocol-payment__metric">
<span class="qc-protocol-payment__metric-label">已收金额</span>
<span class="qc-protocol-payment__metric-value">{{
formatAmount(summary.receivedAmount)
}}</span>
</div>
<div class="qc-protocol-payment__metric">
<span class="qc-protocol-payment__metric-label">待收金额</span>
<span class="qc-protocol-payment__metric-value">{{
formatAmount(summary.pendingAmount)
}}</span>
</div>
</div>
<div v-if="detailRows.length" class="qc-protocol-payment__table-wrap">
<div class="qc-protocol-payment__table-title">
{{ isInstallment ? `缴费明细(共 ${detailRows.length} 期)` : '缴费明细' }}
</div>
<el-table
:data="detailRows"
stripe
size="small"
class="list-table qc-protocol-payment__table"
>
<el-table-column
v-if="isInstallment"
prop="installmentLabel"
label="期次"
min-width="88"
align="center"
/>
<el-table-column
v-if="isInstallment"
prop="installmentDueDate"
label="应缴日期"
min-width="110"
align="center"
>
<template #default="{ row }">{{ row.installmentDueDate || '—' }}</template>
</el-table-column>
<el-table-column label="应缴金额" min-width="110" align="center">
<template #default="{ row }">{{ formatAmount(row.dueAmount) }}</template>
</el-table-column>
<el-table-column label="实收金额" min-width="110" align="center">
<template #default="{ row }">{{ formatAmount(row.transferAmount) }}</template>
</el-table-column>
<el-table-column label="缴费状态" min-width="108" align="center">
<template #default="{ row }">
<el-tag :type="payStatusTagType(row.payStatus)" size="small">
{{ row.payStatusLabel || payStatusLabel(row.payStatus || '') }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
<p v-else class="qc-protocol-payment__empty">暂无缴费明细</p>
</template>
<p v-else class="qc-protocol-payment__empty">暂无缴费信息</p>
</section>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import type { QcProtocolPaymentSummary } from '@/api/qc-work-order'
import { formatMoneyDisplay } from '@/utils/money-format'
import {
payModeTagType as payModeTagTypeGetter,
payStatusLabel,
payStatusTagType
} from '@/utils/status-tag-registry'
import type { TagType } from '@/utils/status-tag-registry'
defineOptions({ name: 'QcWorkOrderProtocolPaymentPanel' })
const props = defineProps<{
summary?: QcProtocolPaymentSummary | null
/** 嵌入查看弹窗时隐藏区块标题,避免与 section 标题重复 */
embedded?: boolean
}>()
const isInstallment = computed(() => props.summary?.payMode === 'fq')
const detailRows = computed(() => props.summary?.paymentDetails || [])
const payModeTagType = computed((): TagType =>
payModeTagTypeGetter(props.summary?.payMode || '')
)
const overallStatusTagType = computed((): TagType => {
const t = props.summary?.overallPayStatusTagType
if (t === 'success' || t === 'warning' || t === 'danger' || t === 'info') return t
return 'info'
})
function formatAmount(val?: number | null) {
if (val == null || Number.isNaN(Number(val))) return '—'
return `¥${formatMoneyDisplay(val)}`
}
</script>
<style scoped lang="scss">
.qc-protocol-payment {
padding: 12px 16px;
background: #ecfdf5;
border-top: 1px solid #d1fae5;
}
.qc-protocol-payment__head {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.qc-protocol-payment__title {
font-size: 13px;
font-weight: 600;
color: #059669;
}
.qc-protocol-payment__metrics {
display: flex;
flex-wrap: wrap;
gap: 12px 24px;
margin-bottom: 12px;
}
.qc-protocol-payment__metric {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 100px;
}
.qc-protocol-payment__metric-label {
font-size: 11px;
color: #64748b;
}
.qc-protocol-payment__metric-value {
font-size: 14px;
font-weight: 600;
color: #1e293b;
}
.qc-protocol-payment__table-title {
margin-bottom: 8px;
font-size: 12px;
font-weight: 600;
color: #334155;
}
.qc-protocol-payment__table-wrap {
min-width: 0;
}
.qc-protocol-payment__table {
width: 100%;
}
.qc-protocol-payment--embedded {
padding: 0;
background: transparent;
border-top: none;
}
.qc-protocol-payment__empty {
margin: 0;
font-size: 12px;
color: #94a3b8;
}
</style>
@@ -0,0 +1,261 @@
<!-- 质检工单 · 同样本分组(上下文条 + Tab + 单工单卡片) -->
<template>
<article class="qc-sample-row">
<div class="qc-sample-row__ctx">
<span class="qc-sample-row__idx">{{ groupIndex }}</span>
<span class="qc-sample-row__code">{{ contextRow.sampleCode || '—' }}</span>
<span class="qc-sample-row__sub">{{ contextSubtitle }}</span>
<span v-if="group.workOrders.length > 1" class="qc-sample-row__badge">
{{ group.workOrders.length }} 条质检
</span>
</div>
<div v-if="group.workOrders.length > 1" class="qc-wo-tabs">
<button
v-for="wo in group.workOrders"
:key="wo.id"
type="button"
class="qc-wo-tab"
:class="{ active: wo.id === activeWorkOrderId }"
@click="activeWorkOrderId = wo.id"
>
<span
class="qc-wo-tab__dot"
:class="
(wo.triggerSource || 'reception') === 'production'
? 'qc-wo-tab__dot--production'
: 'qc-wo-tab__dot--reception'
"
></span>
<span class="qc-wo-tab__no">{{ wo.workOrderNo }}</span>
· {{ triggerSourceTabLabel(wo) }}
<el-tag :type="workOrderStatusTagType(wo.workOrderStatus)" size="small" class="qc-wo-tab__status">
{{ workOrderStatusLabel(wo.workOrderStatus) }}
</el-tag>
</button>
</div>
<QcWorkOrderSingleCard
v-if="activeRow"
layout="inbound-grouped"
:row="activeRow"
:active-type-tab="activeTypeTab"
:task-refresh-token="taskRefreshToken"
@configure="(row) => emit('configure', row)"
@view="(row) => emit('view', row)"
@command="(cmd, row) => emit('command', cmd, row)"
@tasks-changed="emit('tasks-changed')"
/>
</article>
</template>
<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import type { QcWorkOrder } from '@/api/qc-work-order'
import { workOrderStatusLabel } from '@/utils/qc-labels'
import {
protocolStatusLabel,
donationStatusLabel
} from '@/utils/status-tag-registry'
import type { TagType } from '@/utils/status-tag-registry'
import {
type QcWorkOrderSampleGroupModel,
triggerSourceTabLabel
} from '@/utils/qc-work-order-groups'
import QcWorkOrderSingleCard from './QcWorkOrderSingleCard.vue'
defineOptions({ name: 'QcWorkOrderSampleGroup' })
const props = defineProps<{
group: QcWorkOrderSampleGroupModel
groupIndex: number
activeTypeTab: 'inbound' | 'temporary' | 'outbound' | 'all'
taskRefreshToken: number
}>()
const emit = defineEmits<{
configure: [row: QcWorkOrder]
view: [row: QcWorkOrder]
command: [cmd: string, row: QcWorkOrder]
'tasks-changed': []
}>()
const activeWorkOrderId = ref(props.group.workOrders[0]?.id || '')
watch(
() => props.group.workOrders.map((w) => w.id).join(','),
() => {
const ids = props.group.workOrders.map((w) => w.id)
if (!ids.includes(activeWorkOrderId.value)) {
activeWorkOrderId.value = ids[0] || ''
}
}
)
const activeRow = computed(() =>
props.group.workOrders.find((w) => w.id === activeWorkOrderId.value)
)
const contextRow = computed(() => {
const reception =
props.group.workOrders.find((w) => (w.triggerSource || 'reception') === 'reception') ||
props.group.workOrders[0]
return reception
})
function protocolStatusLabelBySource(status: string, source: string): string {
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
}
const contextSubtitle = computed(() => {
const row = contextRow.value
if (!row) return '—'
const parts: string[] = []
if (row.sampleTypeName) parts.push(row.sampleTypeName)
if (row.protocolNo) parts.push(`协议 ${row.protocolNo}`)
if (row.protocolStatus) {
parts.push(
protocolStatusLabelBySource(String(row.protocolStatus), row.receptionSource || 'cell_storage')
)
}
if (row.receptionTime) parts.push(`接收 ${row.receptionTime}`)
if (row.handlerName) parts.push(row.handlerName)
return parts.length ? parts.join(' · ') : '—'
})
function workOrderStatusTagType(status: string): TagType {
if (status === 'ywc') return 'success'
if (status === 'ypz') return 'warning'
if (status === 'yzf') return 'danger'
return 'info'
}
</script>
<style scoped lang="scss">
.qc-sample-row {
display: flex;
flex-direction: column;
min-width: 0;
border: 1px solid #e2e8f0;
border-radius: 10px;
background: #fff;
overflow: hidden;
transition:
border-color 0.15s ease,
box-shadow 0.15s ease;
&:hover {
border-color: #a7f3d0;
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.08);
}
}
.qc-sample-row__ctx {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px 12px;
padding: 12px 16px;
background: #fff;
border-bottom: 1px solid #e2e8f0;
}
.qc-sample-row__idx {
flex-shrink: 0;
font-size: 12px;
color: #94a3b8;
min-width: 20px;
}
.qc-sample-row__code {
font-size: 14px;
font-weight: 600;
color: #1e293b;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.qc-sample-row__sub {
flex: 1;
min-width: 0;
font-size: 12px;
color: #64748b;
line-height: 1.4;
}
.qc-sample-row__badge {
flex-shrink: 0;
font-size: 11px;
font-weight: 600;
padding: 2px 8px;
border-radius: 4px;
background: #fff;
color: #059669;
border: 1px solid #a7f3d0;
}
.qc-wo-tabs {
display: flex;
border-bottom: 1px solid #e2e8f0;
background: #fafafa;
overflow-x: auto;
}
.qc-wo-tab {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 10px 16px;
font-size: 12px;
color: #64748b;
border: none;
border-bottom: 2px solid transparent;
background: transparent;
cursor: pointer;
white-space: nowrap;
transition:
color 0.12s ease,
background 0.12s ease;
&:hover {
color: #334155;
background: #f8fafc;
}
&.active {
color: #059669;
font-weight: 600;
border-bottom-color: #10b981;
background: #fff;
}
}
.qc-wo-tab__no {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.qc-wo-tab__dot {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
flex-shrink: 0;
&--reception {
background: #3b82f6;
}
&--production {
background: #10b981;
}
}
.qc-wo-tab__status {
margin-left: 4px;
}
.qc-sample-row :deep(.qc-work-order-card) {
border: none;
border-radius: 0;
box-shadow: none;
}
</style>
@@ -0,0 +1,520 @@
<!-- 质检工单 · 单工单卡片(head + 任务区) -->
<template>
<article class="qc-work-order-card">
<header class="qc-work-order-card__head">
<div class="qc-work-order-card__head-inner">
<div class="qc-work-order-card__head-main">
<div class="qc-work-order-card__title-row">
<span v-if="cardIndex != null" class="qc-work-order-card__index">{{ cardIndex }}</span>
<span class="qc-work-order-card__no">{{ row.workOrderNo || '—' }}</span>
<el-tag :type="workOrderStatusTagType(row.workOrderStatus)" size="small">
{{ workOrderStatusLabel(row.workOrderStatus) }}
</el-tag>
<el-tag
v-if="showTriggerTag"
:type="triggerSourceTagType(row.triggerSource)"
size="small"
>
{{ row.triggerSourceLabel || triggerSourceTabLabel(row) }}
</el-tag>
</div>
<dl class="qc-work-order-card__meta">
<template v-if="activeTypeTab === 'outbound'">
<div class="qc-work-order-card__meta-item">
<dt>业务类型</dt>
<dd>
<el-tag
:type="
row.bizType === 'pilot_service'
? 'primary'
: row.bizType === 'clinical_application'
? 'warning'
: 'info'
"
size="small"
>
{{ row.bizTypeLabel || '—' }}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>申请单号</dt>
<dd>{{ row.applicationNo || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>用户名称</dt>
<dd>{{ row.patientName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>第几次</dt>
<dd>{{ formatOutboundScheduleSortNo(row) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>总次数</dt>
<dd>{{ formatOutboundScheduleTotalCount(row) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>申请单名称</dt>
<dd>{{ row.applicationName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>渠道名称</dt>
<dd>{{ row.channelName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>输注时间</dt>
<dd>{{ row.infusionTime || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>来源类型</dt>
<dd>
<el-tag
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
size="small"
>
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
</el-tag>
</dd>
</div>
</template>
<template v-else-if="activeTypeTab === 'temporary'">
<div class="qc-work-order-card__meta-item">
<dt>业务类型</dt>
<dd>
<el-tag :type="qcBizTypeTagType('temporary')" size="small">
{{ row.qcBizTypeLabel || qcBizTypeLabel('temporary') }}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>产品编码</dt>
<dd>{{ formatTempCellProductField(row, row.cellProductCode) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>产品名称</dt>
<dd>{{ formatTempCellProductField(row, row.cellProductName) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>产品类型</dt>
<dd>{{ formatTempCellProductField(row, row.cellProductTypeName) }}</dd>
</div>
</template>
<template v-else-if="layout === 'inbound-grouped'">
<div class="qc-work-order-card__meta-item">
<dt>质检对象</dt>
<dd>{{ formatQcTarget(row) }}</dd>
</div>
<div
v-if="(row.triggerSource || 'reception') === 'production'"
class="qc-work-order-card__meta-item"
>
<dt>关联生产工单</dt>
<dd>{{ row.productionWorkOrderNo || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>实验室入库编码</dt>
<dd>{{ row.labStorageCode || '—' }}</dd>
</div>
</template>
<template v-else>
<div class="qc-work-order-card__meta-item">
<dt>样本编码</dt>
<dd>{{ formatTempEmptyField(row, row.sampleCode) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>实验室入库编码</dt>
<dd>{{ formatTempEmptyField(row, row.labStorageCode) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>来源类型</dt>
<dd>
<span v-if="shouldShowTempEmptyField(row, row.receptionSource)">—</span>
<el-tag
v-else
:type="row.receptionSource === 'research_donation' ? 'warning' : 'success'"
size="small"
>
{{ row.receptionSourceLabel || receptionSourceLabel(row.receptionSource || '') }}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>协议状态</dt>
<dd>
<span v-if="shouldShowTempEmptyField(row, row.protocolStatus)">—</span>
<el-tag
v-else
:type="
protocolStatusTagTypeBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
"
size="small"
>
{{
protocolStatusLabelBySource(
String(row.protocolStatus || ''),
row.receptionSource || 'cell_storage'
)
}}
</el-tag>
</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>样本类型</dt>
<dd>{{ row.sampleTypeName || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>接收时间</dt>
<dd>{{ row.receptionTime || '—' }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>接收经手人</dt>
<dd>{{ row.handlerName || '—' }}</dd>
</div>
</template>
<div class="qc-work-order-card__meta-item">
<dt>检测方式</dt>
<dd>{{ formatDetectMethods(row) }}</dd>
</div>
<div class="qc-work-order-card__meta-item">
<dt>创建时间</dt>
<dd>{{ row.createTime || '—' }}</dd>
</div>
<div v-if="row.remark" class="qc-work-order-card__meta-item qc-work-order-card__meta-item--wide">
<dt>备注</dt>
<dd>{{ row.remark }}</dd>
</div>
</dl>
</div>
<div v-if="activeTypeTab !== 'all'" class="qc-work-order-card__ops">
<el-button
v-if="canConfigureWorkOrder(row)"
class="btn-op-item primary"
type="primary"
@click="emit('configure', row)"
>
<el-icon><Setting /></el-icon
>{{ row.workOrderStatus !== 'dpz' ? '调整检测' : '配置检测' }}
</el-button>
<el-button v-else class="btn-op-item primary" @click="emit('view', row)">
<el-icon><View /></el-icon>查看
</el-button>
<el-dropdown
v-if="hasMoreWorkOrderActions(row)"
trigger="hover"
@command="(cmd) => emit('command', 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="canConfigureWorkOrder(row)" command="view">
<el-icon><View /></el-icon>查看
</el-dropdown-item>
<el-dropdown-item
v-if="canEditTemporaryWorkOrder(row) || canEditRemarkWorkOrder(row)"
command="edit"
>
<el-icon><EditPen /></el-icon>编辑
</el-dropdown-item>
<el-dropdown-item v-if="canDeleteWorkOrder(row)" command="delete" divided>
<el-icon><Delete /></el-icon>删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<QcWorkOrderProtocolPaymentPanel
v-if="showProtocolFeeSummary"
:summary="row.paymentSummary"
/>
<QcWorkOrderFeeSummaryBar
v-if="showBasicExperimentFeeSummary"
variant="basic-experiment"
:fee-summary="row.feeSummary"
class="qc-work-order-card__fee-in-head"
/>
</header>
<section v-if="activeTypeTab !== 'all'" class="qc-work-order-card__tasks">
<QcWorkOrderTaskSubList
embedded
:work-order="row"
:refresh-token="taskRefreshToken"
@changed="emit('tasks-changed')"
/>
</section>
</article>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { Setting, View, More, EditPen, Delete } from '@element-plus/icons-vue'
import type { QcWorkOrder } from '@/api/qc-work-order'
import {
workOrderStatusLabel,
receptionSourceLabel,
qcBizTypeLabel
} from '@/utils/qc-labels'
import {
protocolStatusLabel,
protocolStatusTagType,
donationStatusLabel,
donationStatusTagType,
qcBizTypeTagType
} from '@/utils/status-tag-registry'
import type { TagType } from '@/utils/status-tag-registry'
import { triggerSourceTabLabel } from '@/utils/qc-work-order-groups'
import QcWorkOrderTaskSubList from './QcWorkOrderTaskSubList.vue'
import QcWorkOrderFeeSummaryBar from './QcWorkOrderFeeSummaryBar.vue'
import QcWorkOrderProtocolPaymentPanel from './QcWorkOrderProtocolPaymentPanel.vue'
defineOptions({ name: 'QcWorkOrderSingleCard' })
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound' | 'all'
type CardLayout = 'standalone' | 'inbound-grouped'
const props = defineProps<{
row: QcWorkOrder
activeTypeTab: WorkOrderTypeTab
layout?: CardLayout
cardIndex?: number | null
taskRefreshToken: number
}>()
const emit = defineEmits<{
configure: [row: QcWorkOrder]
view: [row: QcWorkOrder]
command: [cmd: string, row: QcWorkOrder]
'tasks-changed': []
}>()
const layout = computed(() => props.layout || 'standalone')
const showTriggerTag = computed(
() => props.activeTypeTab === 'inbound' && layout.value === 'inbound-grouped'
)
const showBasicExperimentFeeSummary = computed(
() => props.activeTypeTab === 'outbound' && props.row.bizType === 'basic_experiment'
)
const showProtocolFeeSummary = computed(() => {
const woType = props.row.workOrderType || 'inbound'
if (woType === 'outbound' || woType === 'temporary') return false
const source = (props.row.receptionSource || 'cell_storage').trim()
return source === 'cell_storage' || source === ''
})
function protocolStatusLabelBySource(status: string, source: string): string {
return source === 'research_donation' ? donationStatusLabel(status) : protocolStatusLabel(status)
}
function protocolStatusTagTypeBySource(status: string, source: string): TagType {
return source === 'research_donation' ? donationStatusTagType(status) : protocolStatusTagType(status)
}
function shouldShowTempEmptyField(row: QcWorkOrder, value?: string | null) {
return row.workOrderType === 'temporary' && !String(value || '').trim()
}
function formatTempEmptyField(row: QcWorkOrder, value?: string | null) {
return shouldShowTempEmptyField(row, value) ? '—' : String(value || '')
}
function formatTempCellProductField(row: QcWorkOrder, value?: string | null) {
if (row.workOrderType !== 'temporary') return '—'
return String(value || '').trim() || '—'
}
function formatOutboundScheduleSortNo(row: Record<string, unknown>) {
const n = row.sortNo ?? row.orderNum
if (n == null || n === '' || Number(n) <= 0) return '—'
return `第${Number(n)}次`
}
function formatOutboundScheduleTotalCount(row: Record<string, unknown>) {
const n = row.totalCourseCount
if (n == null || n === '' || Number(n) <= 0) return '—'
return `共${Number(n)}次`
}
function formatDetectMethods(row: QcWorkOrder) {
const parts: string[] = []
if (row.hasLab) parts.push('实验室')
if (row.hasThirdParty) parts.push('第三方')
return parts.length ? parts.join(' / ') : '—'
}
function formatQcTarget(row: QcWorkOrder) {
if ((row.triggerSource || 'reception') === 'production') {
const parts = [row.cellProductCode, row.cellProductName].filter(Boolean)
return parts.length ? parts.join(' · ') : '—'
}
return '原始样本'
}
function triggerSourceTagType(source?: string): TagType {
return (source || 'reception') === 'production' ? 'warning' : 'primary'
}
function workOrderStatusTagType(status: string): TagType {
if (status === 'ywc') return 'success'
if (status === 'ypz') return 'warning'
if (status === 'yzf') return 'danger'
return 'info'
}
function canConfigureWorkOrder(_row: QcWorkOrder) {
return true
}
function canEditTemporaryWorkOrder(row: QcWorkOrder) {
return (
props.activeTypeTab === 'temporary' ||
(props.activeTypeTab === 'all' && row.workOrderType === 'temporary')
)
}
function canEditRemarkWorkOrder(row: QcWorkOrder) {
if (props.activeTypeTab === 'inbound') return true
if (props.activeTypeTab === 'all' && row.workOrderType !== 'temporary') return true
if (
props.activeTypeTab === 'outbound' &&
row.workOrderStatus !== 'ywc' &&
row.workOrderStatus !== 'yzf'
) {
return true
}
return false
}
function canDeleteWorkOrder(row: QcWorkOrder) {
return (
props.activeTypeTab !== 'outbound' &&
props.activeTypeTab !== 'all' &&
row.workOrderStatus !== 'ywc'
)
}
function hasMoreWorkOrderActions(row: QcWorkOrder) {
if (canConfigureWorkOrder(row)) return true
return canEditTemporaryWorkOrder(row) || canEditRemarkWorkOrder(row) || canDeleteWorkOrder(row)
}
</script>
<style scoped lang="scss">
.qc-work-order-card {
display: flex;
flex-direction: column;
min-width: 0;
border: 1px solid #e2e8f0;
border-radius: 10px;
background: #fff;
overflow: hidden;
}
.qc-work-order-card__head {
display: flex;
flex-direction: column;
gap: 10px;
padding: 14px 16px;
border-bottom: 1px solid #e2e8f0;
background: #fafafa;
}
.qc-work-order-card__head-inner {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 12px 20px;
}
.qc-work-order-card__head-main {
flex: 1;
min-width: 280px;
}
.qc-work-order-card__title-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-bottom: 10px;
}
.qc-work-order-card__index {
flex-shrink: 0;
font-size: 12px;
color: #94a3b8;
min-width: 20px;
}
.qc-work-order-card__no {
font-size: 15px;
font-weight: 600;
color: #1e293b;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
word-break: break-all;
}
.qc-work-order-card__meta {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 8px 12px;
margin: 0;
}
.qc-work-order-card__meta-item {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
dt {
margin: 0;
font-size: 11px;
line-height: 1.35;
color: #94a3b8;
}
dd {
margin: 0;
font-size: 13px;
line-height: 1.4;
color: #334155;
word-break: break-word;
}
&--wide {
grid-column: 1 / -1;
}
}
.qc-work-order-card__fee-in-head {
margin: 10px -16px -14px;
border-top: 1px solid #d1fae5;
border-bottom: none;
}
.qc-work-order-card__ops {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
gap: 8px;
flex-shrink: 0;
align-self: flex-end;
}
.qc-work-order-card__tasks {
background: #f8fafc;
}
.qc-work-order-card__tasks :deep(.qc-work-order-task-sublist) {
padding: 10px 14px 12px;
background: transparent;
}
</style>
@@ -3,7 +3,10 @@
<template>
<div
class="qc-work-order-task-sublist"
:class="{ 'qc-work-order-task-sublist--mine': listMode === 'mine' }"
:class="{
'qc-work-order-task-sublist--mine': listMode === 'mine',
'qc-work-order-task-sublist--embedded': embedded
}"
>
<div class="qc-work-order-task-sublist__panel" v-loading="loading">
<div
@@ -26,7 +29,10 @@
</el-button>
</div>
</div>
<div class="qc-task-cards-row">
<div
v-if="listMode === 'mine'"
class="qc-task-cards-row"
>
<div
v-for="(row, idx) in tableData"
:key="row.id || idx"
@@ -51,7 +57,7 @@
</el-tag>
<el-tag v-else type="info" size="small">待结论</el-tag>
</div>
<div v-if="listMode === 'mine'" class="qc-task-card__context">
<div class="qc-task-card__context">
<span v-if="row.workOrderNo" class="qc-task-card__context-item"
>工单 {{ row.workOrderNo }}</span
>
@@ -70,56 +76,141 @@
{{ row.assigneeUserNames ? `负责人:${row.assigneeUserNames}` : '负责人:—' }}
</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-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 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-dropdown>
<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 class="qc-task-cards-grid">
<div
v-for="(row, idx) in tableData"
:key="row.id || idx"
class="qc-task-card qc-task-card--compact"
@dblclick="handleView(row)"
>
<div class="qc-task-card__line qc-task-card__line--top">
<span class="qc-task-card__name">{{ row.itemName || row.taskNo || '—' }}</span>
<div class="qc-task-card__tags">
<el-tag :type="taskStatusTagType(row.taskStatus)" size="small">
{{ taskStatusLabel(row.taskStatus) }}
</el-tag>
<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>
<el-tag v-else type="info" size="small">待结论</el-tag>
</div>
</div>
<div class="qc-task-card__line qc-task-card__line--bottom">
<span class="qc-task-card__code">{{ row.taskNo || '—' }}</span>
<span class="qc-task-card__sep">·</span>
<span class="qc-task-card__assignees">{{
row.assigneeUserNames || '—'
}}</span>
<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-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>
</div>
<div
@@ -590,6 +681,8 @@
pageSize?: number
/** 父级配置检测成功后递增,用于刷新已展开子列表 */
refreshToken?: number
/** 内嵌于工单卡片时收紧布局 */
embedded?: boolean
}>(),
{
listMode: 'workOrder',
@@ -1487,6 +1580,11 @@
box-sizing: border-box;
}
}
&--embedded {
padding: 0;
background: transparent;
}
}
.qc-work-order-task-sublist__panel {
@@ -1510,6 +1608,24 @@
scrollbar-width: thin;
}
.qc-task-cards-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
@media (max-width: 1200px) {
.qc-task-cards-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.qc-task-cards-grid {
grid-template-columns: 1fr;
}
}
.qc-work-order-task-sublist__head {
display: flex;
align-items: center;
@@ -1616,6 +1732,54 @@
border-color: #a7f3d0;
box-shadow: 0 2px 6px rgba(16, 185, 129, 0.1);
}
&--compact {
min-height: 68px;
flex: unset;
width: auto;
max-width: none;
gap: 5px;
padding: 7px 10px;
}
}
.qc-task-card__line {
display: flex;
align-items: center;
gap: 6px;
min-width: 0;
&--top {
flex-wrap: wrap;
row-gap: 4px;
justify-content: space-between;
}
&--bottom {
flex-wrap: wrap;
row-gap: 4px;
}
}
.qc-task-card__sep {
flex-shrink: 0;
color: #cbd5e1;
font-size: 11px;
}
.qc-task-card--compact .qc-task-card__name {
min-height: auto;
-webkit-line-clamp: 1;
flex: 1;
}
.qc-task-card--compact .qc-task-card__assignees {
min-height: auto;
flex-shrink: 0;
}
.qc-task-card--compact .qc-work-order-task-sublist__ops {
margin-left: auto;
}
.qc-task-card__name {
@@ -46,10 +46,22 @@
<el-option label="已作废" value="yzf" />
</el-select>
</el-form-item>
<el-form-item v-if="activeTypeTab === 'inbound'" label="触发来源">
<el-select
v-model="searchForm.triggerSource"
placeholder="全部"
clearable
style="width: 100%"
>
<el-option label="样本接收" value="reception" />
<el-option label="生产过程" value="production" />
</el-select>
</el-form-item>
<el-form-item v-if="activeTypeTab === 'outbound'" label="业务类型">
<el-select v-model="searchForm.bizType" placeholder="全部" clearable style="width: 100%">
<el-option label="中试服务" value="pilot_service" />
<el-option label="临床应用" value="clinical_application" />
<el-option label="基础实验" value="basic_experiment" />
</el-select>
</el-form-item>
<el-form-item :label="filterTimeLabel">
@@ -267,6 +279,9 @@
:sections="viewSections"
modal-class="qc-work-order-view-dialog-mask"
>
<template #protocol-payment-details>
<QcWorkOrderProtocolPaymentPanel :summary="detail?.paymentSummary" embedded />
</template>
<template #reception-extra>
<div class="view-reception-attachments">
<div class="view-kv view-kv-span-2">
@@ -445,6 +460,7 @@
<script setup lang="ts">
import { formatMoneyDisplay } from '@/utils/money-format'
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
Close,
@@ -511,9 +527,12 @@
import WorkOrderRemarkDialog from '@/components/business/work-order-remark-dialog/index.vue'
import OutboundQcViewDialog from './OutboundQcViewDialog.vue'
import QcWorkOrderCardList from './QcWorkOrderCardList.vue'
import QcWorkOrderProtocolPaymentPanel from './QcWorkOrderProtocolPaymentPanel.vue'
defineOptions({ name: 'QualityInspectionQcWorkOrder' })
const route = useRoute()
const taskSubListRefreshToken = ref(0)
type WorkOrderTypeTab = 'inbound' | 'temporary' | 'outbound' | 'all'
@@ -700,6 +719,9 @@
function handleTypeTabChange() {
pagination.page = 1
if (activeTypeTab.value !== 'inbound') {
searchForm.triggerSource = ''
}
loadData()
}
@@ -745,7 +767,7 @@
return [formatLocalDate(start), formatLocalDate(end)]
}
const searchForm = reactive({ keyword: '', workOrderStatus: '', bizType: '' })
const searchForm = reactive({ keyword: '', workOrderStatus: '', bizType: '', triggerSource: '' })
const createTimeRange = ref<[string, string] | null>(getDefaultLast30DaysRange())
const tableData = ref<QcWorkOrder[]>([])
const loading = ref(false)
@@ -1111,6 +1133,10 @@
transportFields.length > 1 || r.transportType
? [{ title: '运输信息', fields: transportFields }]
: []
const paymentSection =
!isTemp && (d.receptionSource || 'cell_storage') === 'cell_storage'
? [{ title: '协议缴费信息', fields: [], slot: 'protocol-payment-details' }]
: []
return [
{
@@ -1178,6 +1204,7 @@
]
},
...(isTemp ? [] : transportSection),
...(isTemp ? [] : paymentSection),
...(isTemp
? []
: [
@@ -1272,6 +1299,10 @@
workOrderStatus: searchForm.workOrderStatus || undefined,
workOrderType: activeTypeTab.value === 'all' ? undefined : activeTypeTab.value,
bizType: searchForm.bizType || undefined,
triggerSource:
activeTypeTab.value === 'inbound' && searchForm.triggerSource
? searchForm.triggerSource
: undefined,
...timeParams
})
tableData.value = res.list || []
@@ -1289,6 +1320,7 @@
searchForm.keyword = ''
searchForm.workOrderStatus = ''
searchForm.bizType = ''
searchForm.triggerSource = ''
createTimeRange.value = getDefaultLast30DaysRange()
pagination.page = 1
loadData()
@@ -1445,6 +1477,11 @@
)
onMounted(() => {
const sampleCode = String(route.query.sampleCode || '').trim()
if (sampleCode) {
activeTypeTab.value = 'inbound'
searchForm.keyword = sampleCode
}
loadData()
})
</script>