提交
This commit is contained in:
1 parent
0b50eff3d8
commit
ee364e24aa
323 files changed
+57731
-35766
No files matched your search
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="qc-param-select-editor">
|
||||
<div class="qc-param-select-editor__head">
|
||||
单选选项
|
||||
<span class="form-label-tip">多个选项用逗号分隔,第一个为默认选项</span>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="param._optionText"
|
||||
placeholder="例如:阴性,阳性,待复核"
|
||||
@input="syncOptions"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch } from 'vue'
|
||||
import type { QcItemParam } from '@/api/qc-item-param'
|
||||
import {
|
||||
formatQcParamOptionText,
|
||||
parseQcParamOptionText
|
||||
} from '@/utils/qc-item-param-options'
|
||||
|
||||
const param = defineModel<QcItemParam>('param', { required: true })
|
||||
|
||||
function ensureOptionText() {
|
||||
if (param.value._optionText === undefined) {
|
||||
param.value._optionText = formatQcParamOptionText(
|
||||
param.value.options,
|
||||
param.value.defaultValue
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function syncOptions() {
|
||||
const list = parseQcParamOptionText(param.value._optionText)
|
||||
param.value.options = list.length ? JSON.stringify(list) : undefined
|
||||
param.value.defaultValue = list[0] || undefined
|
||||
}
|
||||
|
||||
watch(
|
||||
() => param.value.paramType,
|
||||
() => {
|
||||
if (param.value.paramType === 'select') {
|
||||
ensureOptionText()
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.qc-param-select-editor {
|
||||
padding: 8px 0 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.qc-param-select-editor__head {
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -110,6 +110,7 @@
|
||||
qcTaskConclusionLabel
|
||||
} from '@/utils/qc-labels'
|
||||
import { downloadAttachmentFile } from '@/utils/download-attachment'
|
||||
import { fetchQcInspectionBatches, loadQcInspectionBatches } from '@/utils/qc-inspection-batch'
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean
|
||||
@@ -140,6 +141,8 @@
|
||||
const loading = ref(false)
|
||||
const viewDetail = ref<QcTaskDetail | null>(null)
|
||||
const viewMaterialUsages = ref<ViewMaterialUsageRow[]>([])
|
||||
const viewBatchName = ref('')
|
||||
const viewBatchNo = ref('')
|
||||
const minioBaseUrl = (import.meta.env.VITE_MINIO_BASE_URL || '').replace(/\/$/, '')
|
||||
|
||||
function materialRowsFromApi(items: QcTaskMaterialUsageItem[]): ViewMaterialUsageRow[] {
|
||||
@@ -162,11 +165,28 @@
|
||||
if (!vis || !id) {
|
||||
viewDetail.value = null
|
||||
viewMaterialUsages.value = []
|
||||
viewBatchName.value = ''
|
||||
viewBatchNo.value = ''
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const detail = await fetchQcTaskDetail(id)
|
||||
viewBatchName.value = ''
|
||||
viewBatchNo.value = ''
|
||||
const batchId = (detail.batchId || '').trim()
|
||||
const workOrderId = (detail.workOrderId || '').trim()
|
||||
if (batchId && workOrderId) {
|
||||
try {
|
||||
const batches = await loadQcInspectionBatches(workOrderId)
|
||||
const batch = batches.find((b) => b.id === batchId)
|
||||
viewBatchName.value = batch?.batchName || ''
|
||||
viewBatchNo.value = batch?.batchNo || ''
|
||||
} catch {
|
||||
viewBatchName.value = ''
|
||||
viewBatchNo.value = ''
|
||||
}
|
||||
}
|
||||
try {
|
||||
const results = await fetchQcTaskResults(id)
|
||||
;(detail as QcTaskDetail).results = results || []
|
||||
@@ -188,6 +208,8 @@
|
||||
} catch {
|
||||
viewDetail.value = null
|
||||
viewMaterialUsages.value = []
|
||||
viewBatchName.value = ''
|
||||
viewBatchNo.value = ''
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -360,6 +382,14 @@
|
||||
tagType: qcBizTypeTagType(d.qcBizType || '')
|
||||
},
|
||||
{ label: '工单号', value: d.workOrderNo || '—' },
|
||||
...(viewBatchName.value || viewBatchNo.value
|
||||
? [
|
||||
{
|
||||
label: '检测批次',
|
||||
value: [viewBatchName.value, viewBatchNo.value].filter(Boolean).join(' · ')
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: '工单状态',
|
||||
value: d.workOrderStatus ? workOrderStatusLabel(d.workOrderStatus) : '—',
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
<!-- 样本查看 — 质检信息按检测批次只读展示 -->
|
||||
<template>
|
||||
<div class="sample-qc-batch-readonly" v-loading="loading">
|
||||
<template v-if="batchSections.length">
|
||||
<el-tabs
|
||||
v-model="activeBatchKey"
|
||||
class="panel-pill-tabs panel-pill-tabs--start sample-qc-batch-readonly__tabs"
|
||||
>
|
||||
<el-tab-pane
|
||||
v-for="section in batchSections"
|
||||
:key="section.key"
|
||||
:name="section.key"
|
||||
>
|
||||
<template #label>
|
||||
<span class="sample-qc-batch-readonly__tab-label">{{ section.batchName }}</span>
|
||||
<span class="sample-qc-batch-readonly__tab-count">
|
||||
{{ section.completedTaskCount }}/{{ section.taskCount }}
|
||||
</span>
|
||||
</template>
|
||||
<div
|
||||
v-if="section.batchNo || section.assigneeUserNames"
|
||||
class="sample-qc-batch-readonly__meta"
|
||||
>
|
||||
<span v-if="section.batchNo" class="sample-qc-batch-readonly__meta-item">{{
|
||||
section.batchNo
|
||||
}}</span>
|
||||
<span v-if="section.assigneeUserNames" class="sample-qc-batch-readonly__meta-item">
|
||||
负责人:{{ section.assigneeUserNames }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="qc-detail-cards qc-detail-cards--tasks">
|
||||
<div
|
||||
v-for="task in section.tasks"
|
||||
:key="task.id || `${section.key}-${task.taskNo}`"
|
||||
class="qc-detail-card qc-detail-card--task"
|
||||
>
|
||||
<div class="qc-detail-card__header">
|
||||
<span class="qc-detail-card__name">{{ task.itemName || '—' }}</span>
|
||||
<el-tag :type="taskTypeTagType(task.taskType || '')" size="small">{{
|
||||
task.taskTypeLabel || taskTypeLabel(task.taskType || '')
|
||||
}}</el-tag>
|
||||
</div>
|
||||
<div class="qc-detail-card__body">
|
||||
<div class="qc-kv">
|
||||
<span class="qc-kv__label">任务号</span>
|
||||
<span class="qc-kv__value">{{ task.taskNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="qc-kv">
|
||||
<span class="qc-kv__label">任务状态</span>
|
||||
<span class="qc-kv__value">
|
||||
<el-tag :type="taskStatusTagType(task.taskStatus)" size="small">
|
||||
{{ task.taskStatusLabel || taskStatusLabel(task.taskStatus || '') }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="qc-kv">
|
||||
<span class="qc-kv__label">检测结论</span>
|
||||
<span class="qc-kv__value">
|
||||
<el-tag
|
||||
v-if="task.conclusion"
|
||||
:type="qcTaskConclusionTagType(task.conclusion)"
|
||||
size="small"
|
||||
>
|
||||
{{ task.conclusionLabel || qcTaskConclusionLabel(task.conclusion) }}
|
||||
</el-tag>
|
||||
<span v-else class="qc-kv__muted">—</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="task.id" class="qc-detail-card__foot">
|
||||
<button type="button" class="qc-detail-card__link" @click.stop="emit('view-task', task)">
|
||||
点击查看详情
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
<div v-else-if="!loading" class="sample-qc-batch-readonly__empty hint-muted">
|
||||
暂无检测批次或任务
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import {
|
||||
taskTypeLabel,
|
||||
taskTypeTagType,
|
||||
taskStatusLabel,
|
||||
qcTaskConclusionLabel,
|
||||
qcTaskConclusionTagType
|
||||
} from '@/utils/qc-labels'
|
||||
import { taskStatusTagType } from '@/utils/status-tag-registry'
|
||||
import { loadQcInspectionBatches, resolveBatchSections,
|
||||
type QcBatchTaskSection,
|
||||
type QcInspectionBatch
|
||||
} from '@/utils/qc-inspection-batch'
|
||||
|
||||
export type SampleQcBatchTask = {
|
||||
id?: string
|
||||
taskNo?: string
|
||||
taskType?: string
|
||||
taskTypeLabel?: string
|
||||
itemName?: string
|
||||
taskStatus?: string
|
||||
taskStatusLabel?: string
|
||||
conclusion?: string
|
||||
conclusionLabel?: string
|
||||
batchId?: string
|
||||
}
|
||||
|
||||
defineOptions({ name: 'SampleQcBatchReadonly' })
|
||||
|
||||
const props = defineProps<{
|
||||
workOrderId?: string
|
||||
tasks?: SampleQcBatchTask[]
|
||||
inspectionBatches?: QcInspectionBatch[]
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'view-task': [task: SampleQcBatchTask]
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
const batches = ref<QcInspectionBatch[]>([])
|
||||
const batchSections = ref<QcBatchTaskSection<SampleQcBatchTask>[]>([])
|
||||
const activeBatchKey = ref('')
|
||||
|
||||
function ensureActiveBatchKey(sections: QcBatchTaskSection<SampleQcBatchTask>[]) {
|
||||
if (!sections.length) {
|
||||
activeBatchKey.value = ''
|
||||
return
|
||||
}
|
||||
const keys = new Set(sections.map((s) => s.key))
|
||||
if (!keys.has(activeBatchKey.value)) {
|
||||
activeBatchKey.value = sections[0].key
|
||||
}
|
||||
}
|
||||
|
||||
function syncSections() {
|
||||
batchSections.value = resolveBatchSections(props.inspectionBatches || batches.value, props.tasks)
|
||||
ensureActiveBatchKey(batchSections.value)
|
||||
}
|
||||
|
||||
async function loadBatches() {
|
||||
const woId = (props.workOrderId || '').trim()
|
||||
if (props.inspectionBatches?.length) {
|
||||
batches.value = []
|
||||
syncSections()
|
||||
return
|
||||
}
|
||||
if (!woId) {
|
||||
batches.value = []
|
||||
syncSections()
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
batches.value = await loadQcInspectionBatches(woId)
|
||||
} catch {
|
||||
batches.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
syncSections()
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.workOrderId, props.tasks, props.inspectionBatches] as const,
|
||||
() => {
|
||||
if (props.inspectionBatches?.length) {
|
||||
batches.value = []
|
||||
syncSections()
|
||||
return
|
||||
}
|
||||
if (props.workOrderId) {
|
||||
loadBatches()
|
||||
return
|
||||
}
|
||||
syncSections()
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.sample-qc-batch-readonly__tabs {
|
||||
&.panel-pill-tabs.el-tabs > :deep(.el-tabs__header) {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
&.panel-pill-tabs.el-tabs :deep(.el-tabs__nav-scroll) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
&.panel-pill-tabs.el-tabs :deep(.el-tabs__item) {
|
||||
min-width: 96px;
|
||||
padding: 6px 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sample-qc-batch-readonly__tab-label {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.sample-qc-batch-readonly__tab-count {
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.sample-qc-batch-readonly__meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 16px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--mint-text-muted, #64748b);
|
||||
}
|
||||
|
||||
.sample-qc-batch-readonly__empty {
|
||||
padding: 8px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.qc-detail-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
gap: 10px;
|
||||
|
||||
&--tasks {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-detail-card {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.qc-detail-card__header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.qc-detail-card__name {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.qc-detail-card__body {
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.qc-detail-card__foot {
|
||||
padding: 2px 12px 8px;
|
||||
text-align: right;
|
||||
border-top: 1px dashed #f1f5f9;
|
||||
}
|
||||
|
||||
.qc-detail-card__link {
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
color: #047857;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #065f46;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-kv__muted {
|
||||
color: var(--mint-text-muted, #334155);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.qc-kv {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.qc-kv__label {
|
||||
color: var(--mint-text-muted, #334155);
|
||||
flex-shrink: 0;
|
||||
min-width: 56px;
|
||||
}
|
||||
|
||||
.qc-kv__value {
|
||||
color: #1e293b;
|
||||
font-weight: 500;
|
||||
word-break: break-word;
|
||||
}
|
||||
</style>
|
||||
@@ -32,56 +32,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="qcInfo.workOrderStatus === 'dpz' && !qcInfo.tasks?.length" class="sample-qc-hint">
|
||||
<div
|
||||
v-if="qcInfo.workOrderStatus === 'dpz' && !hasTaskContent"
|
||||
class="sample-qc-hint"
|
||||
>
|
||||
工单待配置检测项目
|
||||
</div>
|
||||
|
||||
<div v-if="qcInfo.tasks?.length" class="qc-detail-cards qc-detail-cards--tasks">
|
||||
<div
|
||||
v-for="task in qcInfo.tasks"
|
||||
:key="task.id"
|
||||
class="qc-detail-card qc-detail-card--task"
|
||||
>
|
||||
<div class="qc-detail-card__header">
|
||||
<span class="qc-detail-card__name">{{ task.itemName || '—' }}</span>
|
||||
<el-tag :type="taskTypeTagType(task.taskType || '')" size="small">{{
|
||||
task.taskTypeLabel || taskTypeLabel(task.taskType || '')
|
||||
}}</el-tag>
|
||||
</div>
|
||||
<div class="qc-detail-card__body">
|
||||
<div class="qc-kv">
|
||||
<span class="qc-kv__label">任务号</span>
|
||||
<span class="qc-kv__value">{{ task.taskNo || '—' }}</span>
|
||||
</div>
|
||||
<div class="qc-kv">
|
||||
<span class="qc-kv__label">任务状态</span>
|
||||
<span class="qc-kv__value">
|
||||
<el-tag :type="taskStatusTagType(task.taskStatus)" size="small">
|
||||
{{ task.taskStatusLabel || taskStatusLabel(task.taskStatus || '') }}
|
||||
</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
<div class="qc-kv">
|
||||
<span class="qc-kv__label">检测结论</span>
|
||||
<span class="qc-kv__value">
|
||||
<el-tag
|
||||
v-if="task.conclusion"
|
||||
:type="qcTaskConclusionTagType(task.conclusion)"
|
||||
size="small"
|
||||
>
|
||||
{{ task.conclusionLabel || qcTaskConclusionLabel(task.conclusion) }}
|
||||
</el-tag>
|
||||
<span v-else class="qc-kv__muted">—</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qc-detail-card__foot">
|
||||
<button type="button" class="qc-detail-card__link" @click.stop="openTaskView(task)">
|
||||
点击查看详情
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SampleQcBatchReadonly
|
||||
v-if="hasTaskContent"
|
||||
:work-order-id="qcInfo.id"
|
||||
:tasks="qcInfo.tasks"
|
||||
:inspection-batches="qcInfo.inspectionBatches"
|
||||
@view-task="openTaskView"
|
||||
/>
|
||||
|
||||
<div v-else-if="qcInfo.workOrderStatus !== 'dpz'" class="sample-qc-hint"> 暂无检测任务 </div>
|
||||
</template>
|
||||
@@ -98,17 +62,11 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import {
|
||||
qcBizTypeLabel,
|
||||
workOrderStatusLabel,
|
||||
taskTypeLabel,
|
||||
taskTypeTagType,
|
||||
taskStatusLabel,
|
||||
qcTaskConclusionLabel,
|
||||
qcTaskConclusionTagType
|
||||
} from '@/utils/qc-labels'
|
||||
import { workOrderStatusTagType, taskStatusTagType } from '@/utils/status-tag-registry'
|
||||
import { qcBizTypeLabel, workOrderStatusLabel } from '@/utils/qc-labels'
|
||||
import { workOrderStatusTagType } from '@/utils/status-tag-registry'
|
||||
import type { QcInspectionBatch } from '@/utils/qc-inspection-batch'
|
||||
import QcTaskViewDialog from '@/components/business/qc-task-view-dialog/index.vue'
|
||||
import SampleQcBatchReadonly from '@/components/business/sample-qc-batch-readonly/index.vue'
|
||||
|
||||
export type SampleQcTask = {
|
||||
id?: string
|
||||
@@ -124,9 +82,11 @@
|
||||
conclusionLabel?: string
|
||||
completedTime?: string
|
||||
remark?: string
|
||||
batchId?: string
|
||||
}
|
||||
|
||||
export type SampleQcInfo = {
|
||||
id?: string
|
||||
workOrderNo?: string
|
||||
workOrderStatus?: string
|
||||
workOrderStatusLabel?: string
|
||||
@@ -147,6 +107,7 @@
|
||||
itemName?: string
|
||||
companyName?: string
|
||||
}>
|
||||
inspectionBatches?: QcInspectionBatch[]
|
||||
tasks?: SampleQcTask[]
|
||||
}
|
||||
|
||||
@@ -172,6 +133,11 @@
|
||||
const taskViewVisible = ref(false)
|
||||
const taskViewId = ref('')
|
||||
|
||||
const hasTaskContent = computed(
|
||||
() =>
|
||||
!!(props.qcInfo?.inspectionBatches?.length || props.qcInfo?.tasks?.length)
|
||||
)
|
||||
|
||||
const emptyHint = computed(() => {
|
||||
const rec = props.sampleReception
|
||||
if (!rec) {
|
||||
@@ -236,74 +202,6 @@
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.qc-detail-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
gap: 10px;
|
||||
|
||||
&--tasks {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-detail-card {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.qc-detail-card__header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid #f1f5f9;
|
||||
}
|
||||
|
||||
.qc-detail-card__name {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #1e293b;
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.qc-detail-card__body {
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.qc-detail-card__foot {
|
||||
padding: 2px 12px 8px;
|
||||
text-align: right;
|
||||
border-top: 1px dashed #f1f5f9;
|
||||
}
|
||||
|
||||
.qc-detail-card__link {
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: none;
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
color: #047857;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #065f46;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.qc-kv__muted {
|
||||
color: var(--mint-text-muted, #334155);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.qc-kv {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
+49
-4
@@ -4,8 +4,12 @@
|
||||
<ArtSvgIcon :icon="item.meta.icon" :color="theme?.iconColor" class="mr-1 text-lg" />
|
||||
<span class="text-md">{{ formatMenuTitle(item.meta.title) }}</span>
|
||||
<div v-if="item.meta.showBadge" class="art-badge art-badge-horizontal" />
|
||||
<div v-if="item.meta.showTextBadge" class="art-text-badge">
|
||||
{{ item.meta.showTextBadge }}
|
||||
<div
|
||||
v-if="resolveMenuTextBadge(item)"
|
||||
class="art-text-badge"
|
||||
:class="menuTextBadgeClass(item)"
|
||||
>
|
||||
{{ resolveMenuTextBadge(item) }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -38,8 +42,8 @@
|
||||
class="art-badge"
|
||||
:style="{ right: level === 0 ? '10px' : '20px' }"
|
||||
/>
|
||||
<div v-if="item.meta.showTextBadge && level !== 0" class="art-text-badge">
|
||||
{{ item.meta.showTextBadge }}
|
||||
<div v-if="resolveMenuTextBadge(item)" class="art-text-badge" :class="menuTextBadgeClass(item)">
|
||||
{{ resolveMenuTextBadge(item) }}
|
||||
</div>
|
||||
</ElMenuItem>
|
||||
</template>
|
||||
@@ -49,6 +53,12 @@
|
||||
import { AppRouteRecord } from '@/types/router'
|
||||
import { handleMenuJump } from '@/utils/navigation'
|
||||
import { formatMenuTitle } from '@/utils/router'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useQcMenuBadgeStore } from '@/store/modules/qc-menu-badge'
|
||||
import { useProductionMenuBadgeStore } from '@/store/modules/production-menu-badge'
|
||||
import { resolveQcMenuBadgeCode } from '@/utils/qc-menu-badge'
|
||||
import { resolveProductionMenuBadgeCode } from '@/utils/production-menu-badge'
|
||||
import { formatQcWorkOrderTabBadgeCount } from '@/api/qc-work-order'
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
@@ -67,6 +77,41 @@
|
||||
})
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
const qcMenuBadgeStore = useQcMenuBadgeStore()
|
||||
const productionMenuBadgeStore = useProductionMenuBadgeStore()
|
||||
const { loadedMenuCodes, badgeByMenuCode } = storeToRefs(qcMenuBadgeStore)
|
||||
const { loadedMenuCodes: productionLoadedMenuCodes } = storeToRefs(productionMenuBadgeStore)
|
||||
|
||||
function resolveMenuTextBadge(item: AppRouteRecord): string {
|
||||
const productionMenuCode = resolveProductionMenuBadgeCode(item)
|
||||
if (productionMenuCode && productionLoadedMenuCodes.value.includes(productionMenuCode)) {
|
||||
return productionMenuBadgeStore.getBadgeText(productionMenuCode)
|
||||
}
|
||||
const menuCode = resolveQcMenuBadgeCode(item)
|
||||
if (menuCode && loadedMenuCodes.value.includes(menuCode)) {
|
||||
const count = badgeByMenuCode.value[menuCode] ?? 0
|
||||
return formatQcWorkOrderTabBadgeCount(count)
|
||||
}
|
||||
if (item.meta.showTextBadge && props.level !== 0) {
|
||||
return item.meta.showTextBadge
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function menuTextBadgeClass(item: AppRouteRecord): Record<string, boolean> {
|
||||
const productionMenuCode = resolveProductionMenuBadgeCode(item)
|
||||
if (productionMenuCode && productionLoadedMenuCodes.value.includes(productionMenuCode)) {
|
||||
return {
|
||||
'art-text-badge--zero': productionMenuBadgeStore.isBadgeZero(productionMenuCode),
|
||||
'art-text-badge--dual': true
|
||||
}
|
||||
}
|
||||
const menuCode = resolveQcMenuBadgeCode(item)
|
||||
if (menuCode && loadedMenuCodes.value.includes(menuCode)) {
|
||||
return { 'art-text-badge--zero': (badgeByMenuCode.value[menuCode] ?? 0) === 0 }
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
// 过滤后的子菜单项(不包含隐藏的)
|
||||
const filteredChildren = computed(() => {
|
||||
|
||||
@@ -157,6 +157,7 @@ $popup-menu-radius: 6px;
|
||||
// 菜单高度
|
||||
.el-sub-menu__title,
|
||||
.el-menu-item {
|
||||
position: relative;
|
||||
display: flex !important;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
@@ -165,6 +166,15 @@ $popup-menu-radius: 6px;
|
||||
line-height: $menu-height !important;
|
||||
overflow: hidden !important;
|
||||
|
||||
.menu-title-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
padding-right: 28px;
|
||||
}
|
||||
|
||||
.menu-name {
|
||||
flex-shrink: 1;
|
||||
min-width: 0;
|
||||
|
||||
+53
-6
@@ -54,12 +54,18 @@
|
||||
/>
|
||||
|
||||
<template #title>
|
||||
<span class="menu-name">
|
||||
{{ formatMenuTitle(item.meta.title) }}
|
||||
</span>
|
||||
<div v-if="item.meta.showBadge" class="art-badge" />
|
||||
<div v-if="item.meta.showTextBadge && (level > 0 || menuOpen)" class="art-text-badge">
|
||||
{{ item.meta.showTextBadge }}
|
||||
<div class="menu-title-wrap">
|
||||
<span class="menu-name">
|
||||
{{ formatMenuTitle(item.meta.title) }}
|
||||
</span>
|
||||
<div v-if="item.meta.showBadge" class="art-badge" />
|
||||
<div
|
||||
v-if="resolveMenuTextBadge(item)"
|
||||
class="art-text-badge"
|
||||
:class="menuTextBadgeClass(item)"
|
||||
>
|
||||
{{ resolveMenuTextBadge(item) }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ElMenuItem>
|
||||
@@ -73,6 +79,11 @@
|
||||
import { filterSidebarRoutes } from '@/utils/router/sidebar-menu-filter'
|
||||
import { handleMenuJump } from '@/utils/navigation'
|
||||
import { useSettingStore } from '@/store/modules/setting'
|
||||
import { useQcMenuBadgeStore } from '@/store/modules/qc-menu-badge'
|
||||
import { useProductionMenuBadgeStore } from '@/store/modules/production-menu-badge'
|
||||
import { resolveQcMenuBadgeCode } from '@/utils/qc-menu-badge'
|
||||
import { resolveProductionMenuBadgeCode } from '@/utils/production-menu-badge'
|
||||
import { formatQcWorkOrderTabBadgeCount } from '@/api/qc-work-order'
|
||||
|
||||
interface MenuTheme {
|
||||
iconColor?: string
|
||||
@@ -107,8 +118,12 @@
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const qcMenuBadgeStore = useQcMenuBadgeStore()
|
||||
const productionMenuBadgeStore = useProductionMenuBadgeStore()
|
||||
|
||||
const { menuOpen } = storeToRefs(settingStore)
|
||||
const { loadedMenuCodes, badgeByMenuCode } = storeToRefs(qcMenuBadgeStore)
|
||||
const { loadedMenuCodes: productionLoadedMenuCodes } = storeToRefs(productionMenuBadgeStore)
|
||||
|
||||
/**
|
||||
* 过滤后的菜单项列表
|
||||
@@ -116,6 +131,38 @@
|
||||
*/
|
||||
const filteredMenuItems = computed(() => filterSidebarRoutes(props.list || []))
|
||||
|
||||
function resolveMenuTextBadge(item: AppRouteRecord): string {
|
||||
const productionMenuCode = resolveProductionMenuBadgeCode(item)
|
||||
if (productionMenuCode && productionLoadedMenuCodes.value.includes(productionMenuCode)) {
|
||||
return productionMenuBadgeStore.getBadgeText(productionMenuCode)
|
||||
}
|
||||
const menuCode = resolveQcMenuBadgeCode(item)
|
||||
if (menuCode && loadedMenuCodes.value.includes(menuCode)) {
|
||||
const count = badgeByMenuCode.value[menuCode] ?? 0
|
||||
return formatQcWorkOrderTabBadgeCount(count)
|
||||
}
|
||||
const staticBadge = item.meta.showTextBadge
|
||||
if (staticBadge && (props.level > 0 || menuOpen.value)) {
|
||||
return staticBadge
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function menuTextBadgeClass(item: AppRouteRecord): Record<string, boolean> {
|
||||
const productionMenuCode = resolveProductionMenuBadgeCode(item)
|
||||
if (productionMenuCode && productionLoadedMenuCodes.value.includes(productionMenuCode)) {
|
||||
return {
|
||||
'art-text-badge--zero': productionMenuBadgeStore.isBadgeZero(productionMenuCode),
|
||||
'art-text-badge--dual': true
|
||||
}
|
||||
}
|
||||
const menuCode = resolveQcMenuBadgeCode(item)
|
||||
if (menuCode && loadedMenuCodes.value.includes(menuCode)) {
|
||||
return { 'art-text-badge--zero': (badgeByMenuCode.value[menuCode] ?? 0) === 0 }
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到指定页面
|
||||
* @param item 菜单项数据
|
||||
|
||||
Reference in new issue
Block a user