优化pagetype已读用户布局样式

This commit is contained in:
jingrow 2025-10-13 18:13:40 +08:00
parent 124ce6d5dd
commit 1a9808f6a5

View File

@ -74,10 +74,21 @@
v-show="shouldShowField(field)"
>
<div class="field-label">
<label>{{ t(field.label || field.fieldname) }}</label>
<span v-if="field.reqd" class="required">*</span>
<template v-if="field.fieldname === 'seen_by'">
<div class="seen-by-header" @click="toggleSeenBy()">
<label>{{ t(field.label || field.fieldname) }}</label>
<span class="seen-by-count">{{ seenByUsers.length }}</span>
<n-icon size="16" class="chevron-icon">
<Icon :icon="seenByExpanded ? 'tabler:chevron-up' : 'tabler:chevron-down'" />
</n-icon>
</div>
</template>
<template v-else>
<label>{{ t(field.label || field.fieldname) }}</label>
<span v-if="field.reqd" class="required">*</span>
</template>
</div>
<div class="field-content">
<div class="field-content" :class="{ 'seen-by-collapsed': field.fieldname === 'seen_by' && !seenByExpanded }">
<!-- 文本类型字段 -->
<template v-if="['Data', 'Password', 'Phone', 'Barcode'].includes(field.fieldtype)">
<n-input
@ -186,7 +197,8 @@
<!-- 日期时间类型字段 -->
<template v-else-if="field.fieldtype === 'Date'">
<n-date-picker
v-model:value="record[field.fieldname]"
:value="toDateValue(record[field.fieldname])"
@update:value="(v)=> updateDateValue(field.fieldname, v)"
type="date"
:placeholder="t(field.fieldname)"
:disabled="!canEdit"
@ -341,16 +353,14 @@
</template>
<template v-else-if="field.fieldtype === 'Table'">
<!-- 专门渲染 seen_by 子表为简洁表格 -->
<template v-if="field.fieldname === 'seen_by'">
<n-data-table
:columns="seenByColumns"
:data="getSeenByData()"
size="small"
:bordered="false"
:single-line="true"
:pagination="false"
/>
<transition name="fade">
<div v-show="seenByExpanded" class="seen-by-chips">
<n-tag v-for="u in seenByUsers" :key="u.key" size="small" round class="seen-by-chip" :bordered="false">
<span class="chip-text">{{ u.label }}</span>
</n-tag>
</div>
</transition>
</template>
<template v-else>
<div class="table-container">
@ -423,7 +433,7 @@
<script setup lang="ts">
import { onMounted, ref, computed, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NButton, NSpace, NIcon, NProgress, NInput, NSelect, NInputNumber, NCheckbox, NDatePicker, NTimePicker, NRate, NColorPicker, NAutoComplete, NDataTable, useMessage } from 'naive-ui'
import { NButton, NSpace, NIcon, NProgress, NInput, NSelect, NInputNumber, NCheckbox, NDatePicker, NTimePicker, NRate, NColorPicker, NAutoComplete, NTag, useMessage } from 'naive-ui'
import JeditorControl from '../../components/form/controls/Jeditor.vue'
import { Icon } from '@iconify/vue'
import axios from 'axios'
@ -663,16 +673,20 @@ function getSelectOptions(field: any) {
return options.map((opt: string) => ({ label: t(opt), value: opt }))
}
// Seen By
const seenByColumns = [
{ title: t('User'), key: 'user' }
]
// 使使
function getSeenByData() {
//
const seenByExpanded = ref(false)
const seenByUsers = computed(() => {
const list = Array.isArray(record.value?.seen_by) ? record.value.seen_by : []
return list.map((item: any) => ({
user: item.user || item.owner || '—'
return list.map((item: any, idx: number) => ({
key: item.name || item.user || String(idx),
label: item.user || item.owner || '—'
}))
})
function toggleSeenBy() {
seenByExpanded.value = !seenByExpanded.value
}
// jingrow
@ -783,6 +797,31 @@ function formatDateTime(value: any) {
}
}
// Naive UI DatePicker number(timestamp) [number, number]
function toDateValue(v: any): number | null {
if (!v) return null
// Date
if (typeof v === 'number') return v
if (v instanceof Date) return v.getTime()
// 'YYYY-MM-DD' ISO
const parsed = new Date(v)
if (!isNaN(parsed.getTime())) return parsed.getTime()
return null
}
function updateDateValue(fieldname: string, v: number | null) {
if (v === null || v === undefined) {
record.value[fieldname] = null
} else {
// 'YYYY-MM-DD'
const d = new Date(v)
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
record.value[fieldname] = `${y}-${m}-${day}`
}
}
function formatJson(value: any) {
if (!value) return ''
try {
@ -1257,6 +1296,47 @@ watch(() => route.params.id, async (newId, oldId) => {
min-height: 40px;
}
/* Seen By 折叠与徽章样式 */
.seen-by-block {
width: 100%;
}
.seen-by-header {
display: inline-flex;
align-items: center;
gap: 8px;
cursor: pointer;
color: #374151;
user-select: none;
}
.seen-by-title {
font-weight: 500;
}
.seen-by-count {
margin: 0 6px;
color: #9ca3af;
font-size: 12px;
}
.seen-by-chips {
margin-top: 10px;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.seen-by-chip {
background: #f3f4f6;
}
.chip-text {
padding: 0 2px;
}
.fade-enter-active, .fade-leave-active { transition: opacity .15s ease; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
/* 收起态去除多余高度与间距 */
.field-content.seen-by-collapsed {
min-height: 0;
padding: 0;
}
/* 统一的系统信息页脚 */
.meta-footer {
display: flex;