黄伟杰 2 days ago
commit 2711561233

@ -307,9 +307,9 @@ onMounted(() => { loadDictAndUnits() })
</script>
<style lang="scss" scoped>
.page-container { min-height: 100vh; background: #f5f7fb; }
.detail-scroll { height: calc(100vh - 172rpx); }
.content-section { padding: 20rpx 24rpx 28rpx; }
.page-container { min-height: 100vh; background: #f5f7fb; display: flex; flex-direction: column; }
.detail-scroll { flex: 1; overflow-y: auto; }
.content-section { padding: 20rpx 24rpx 160rpx; }
.section-card { background: #ffffff; border-radius: 20rpx; padding: 24rpx; margin-bottom: 20rpx; border: 1rpx solid #eef2f7; box-shadow: 0 6rpx 18rpx rgba(15, 23, 42, 0.04); }
.section-header { display: flex; align-items: center; gap: 12rpx; margin-bottom: 22rpx; padding-bottom: 18rpx; border-bottom: 1rpx solid #f1f5f9; }
.section-icon { width: 40rpx; height: 40rpx; border-radius: 10rpx; background: #eff6ff; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }

@ -65,31 +65,28 @@
<view v-if="currentTab === 0">
<!-- 搜索栏 -->
<view class="search-bar">
<view class="search-row">
<view class="search-field">
<view class="search-bar compact">
<!-- 第一行编码输入框 + 下拉箭头 + 操作图标 -->
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">编码</text>
<input v-model="childSearchCode" class="search-input" placeholder="请输入编码" confirm-type="search" @confirm="handleChildSearch" />
<input v-model="childSearchCode" class="search-input" placeholder="请输入编码" @input="handleChildSearch" />
</view>
<view class="search-field">
<text class="search-label">名称</text>
<input v-model="childSearchName" class="search-input" placeholder="请输入名称" confirm-type="search" @confirm="handleChildSearch" />
<view class="search-toggle" @click="childSearchExpanded = !childSearchExpanded">
<uni-icons :type="childSearchExpanded ? 'arrow-up' : 'arrow-down'" size="14" color="#64748b"></uni-icons>
</view>
</view>
<view class="search-btns">
<view class="search-btn primary" @click="handleChildSearch">
<uni-icons type="search" size="16" color="#fff"></uni-icons>
<text>查询</text>
</view>
<view class="search-btn" @click="resetChildSearch">
<uni-icons type="refresh" size="16" color="#fff"></uni-icons>
<text>重置</text>
<view class="search-icon-btn reset" @click="resetChildSearch">
<uni-icons type="refresh" size="18" color="#64748b"></uni-icons>
</view>
<view class="search-btn add" @click="goAddChildMold">
<uni-icons type="plusempty" size="16" color="#fff"></uni-icons>
<text>新增</text>
<view class="search-icon-btn add" @click="goAddChildMold">
<uni-icons type="plusempty" size="18" color="#64748b"></uni-icons>
</view>
</view>
<!-- 展开后显示的名称输入框 -->
<view v-show="childSearchExpanded" class="search-field compact-field">
<text class="search-label">名称</text>
<input v-model="childSearchName" class="search-input" placeholder="请输入名称" @input="handleChildSearch" />
</view>
</view>
<view v-if="childLoading" class="hint">{{ t('functionCommon.loading') }}</view>
<view v-else-if="!filteredChildMolds.length" class="hint">{{ t('moldLedger.noChildMold') }}</view>
@ -124,6 +121,26 @@
</view>
<view v-else-if="currentTab === 1">
<!-- 搜索栏 -->
<view class="search-bar compact">
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">开始时间</text>
<picker mode="date" :value="inspectionStartDate" @change="onInspectionStartChange" class="search-picker">
<view class="search-picker-value">{{ inspectionStartDate || '请选择' }}</view>
</picker>
</view>
<view class="search-field compact-field">
<text class="search-label">结束时间</text>
<picker mode="date" :value="inspectionEndDate" @change="onInspectionEndChange" class="search-picker">
<view class="search-picker-value">{{ inspectionEndDate || '请选择' }}</view>
</picker>
</view>
<view class="search-icon-btn" @click="resetInspectionSearch">
<uni-icons type="refresh" size="18" color="#64748b"></uni-icons>
</view>
</view>
</view>
<view v-if="inspectionLoading" class="hint">{{ t('functionCommon.loading') }}</view>
<view v-else-if="!inspectionGroups.length" class="hint">{{ t('moldLedger.noInspection') }}</view>
<view v-for="group in inspectionGroups" :key="group.key" class="record-card">
@ -153,6 +170,47 @@
</view>
<view v-else-if="currentTab === 2">
<!-- 搜索栏 -->
<view class="search-bar compact">
<!-- 第一行维修单号 + 下拉箭头 + 重置 -->
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">单号</text>
<input v-model="repairSearchCode" class="search-input" placeholder="请输入维修单号" @input="handleRepairSearch" />
</view>
<view class="search-toggle" @click="repairSearchExpanded = !repairSearchExpanded">
<uni-icons :type="repairSearchExpanded ? 'arrow-up' : 'arrow-down'" size="14" color="#64748b"></uni-icons>
</view>
<view class="search-icon-btn" @click="resetRepairSearch">
<uni-icons type="refresh" size="18" color="#64748b"></uni-icons>
</view>
</view>
<!-- 展开后显示的更多搜索条件 -->
<view v-show="repairSearchExpanded" class="search-expand-area">
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">状态</text>
<picker mode="selector" :range="repairStatusOptions" range-key="label" :value="repairStatusIndex" @change="onRepairStatusChange" class="search-picker">
<view class="search-picker-value">{{ repairStatusOptions[repairStatusIndex]?.label || '全部' }}</view>
</picker>
</view>
</view>
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">开始时间</text>
<picker mode="date" :value="repairStartDate" @change="onRepairStartChange" class="search-picker">
<view class="search-picker-value">{{ repairStartDate || '请选择' }}</view>
</picker>
</view>
<view class="search-field compact-field">
<text class="search-label">结束时间</text>
<picker mode="date" :value="repairEndDate" @change="onRepairEndChange" class="search-picker">
<view class="search-picker-value">{{ repairEndDate || '请选择' }}</view>
</picker>
</view>
</view>
</view>
</view>
<view v-if="repairLoading" class="hint">{{ t('functionCommon.loading') }}</view>
<view v-else-if="!repairRecords.length" class="hint">{{ t('moldLedger.noRepair') }}</view>
<view v-for="row in repairRecords" :key="row.key" class="record-card" @click="openRepairDetail(row)">
@ -176,6 +234,26 @@
</view>
<view v-else-if="currentTab === 3">
<!-- 搜索栏 -->
<view class="search-bar compact">
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">开始时间</text>
<picker mode="date" :value="maintainStartDate" @change="onMaintainStartChange" class="search-picker">
<view class="search-picker-value">{{ maintainStartDate || '请选择' }}</view>
</picker>
</view>
<view class="search-field compact-field">
<text class="search-label">结束时间</text>
<picker mode="date" :value="maintainEndDate" @change="onMaintainEndChange" class="search-picker">
<view class="search-picker-value">{{ maintainEndDate || '请选择' }}</view>
</picker>
</view>
<view class="search-icon-btn" @click="resetMaintainSearch">
<uni-icons type="refresh" size="18" color="#64748b"></uni-icons>
</view>
</view>
</view>
<view v-if="maintainLoading" class="hint">{{ t('functionCommon.loading') }}</view>
<view v-else-if="!maintainGroups.length" class="hint">{{ t('moldLedger.noMaintenance') }}</view>
<view v-for="group in maintainGroups" :key="group.key" class="record-card">
@ -204,7 +282,40 @@
</view>
</view>
<view v-else>
<view v-else-if="currentTab === 4">
<!-- 搜索栏 -->
<view class="search-bar compact">
<!-- 默认显示开始时间 + 结束时间 + 下拉箭头 + 重置 -->
<view class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">开始时间</text>
<picker mode="date" :value="installStartDate" @change="onInstallStartChange" class="search-picker">
<view class="search-picker-value">{{ installStartDate || '请选择' }}</view>
</picker>
</view>
<view class="search-field compact-field">
<text class="search-label">结束时间</text>
<picker mode="date" :value="installEndDate" @change="onInstallEndChange" class="search-picker">
<view class="search-picker-value">{{ installEndDate || '请选择' }}</view>
</picker>
</view>
<view class="search-toggle" @click="installSearchExpanded = !installSearchExpanded">
<uni-icons :type="installSearchExpanded ? 'arrow-up' : 'arrow-down'" size="14" color="#64748b"></uni-icons>
</view>
<view class="search-icon-btn" @click="resetInstallSearch">
<uni-icons type="refresh" size="18" color="#64748b"></uni-icons>
</view>
</view>
<!-- 展开后显示操作类型 -->
<view v-show="installSearchExpanded" class="search-row compact-row">
<view class="search-field compact-field">
<text class="search-label">操作类型</text>
<picker mode="selector" :range="installOperateOptions" range-key="label" :value="installOperateIndex" @change="onInstallOperateChange" class="search-picker">
<view class="search-picker-value">{{ installOperateOptions[installOperateIndex]?.label || '全部' }}</view>
</picker>
</view>
</view>
</view>
<view v-if="installLoading" class="hint">{{ t('functionCommon.loading') }}</view>
<view v-else-if="!installRecords.length" class="hint">{{ t('moldLedger.noInstall') }}</view>
<view v-for="row in installRecords" :key="String(row.id || row.createTime)" class="record-card">
@ -221,6 +332,62 @@
<view class="record-row"><text class="record-label">{{ t('moldLedger.remark') }}</text><text class="record-value">{{
detailValue(row.remark) }}</text></view>
</view>
<!-- 分页 -->
<view v-if="installTotal > installPageSize" class="pagination-bar">
<view class="pagination-btn" :class="{ disabled: installPageNo <= 1 }" @click="installPrevPage">
<text>上一页</text>
</view>
<text class="pagination-info">{{ installPageNo }} / {{ Math.ceil(installTotal / installPageSize) }}</text>
<view class="pagination-btn" :class="{ disabled: installPageNo >= Math.ceil(installTotal / installPageSize) }" @click="installNextPage">
<text>下一页</text>
</view>
</view>
</view>
<!-- Tab5: 图纸 -->
<view v-else-if="currentTab === 5">
<view v-if="!drawingRows.length" class="hint"></view>
<view v-for="(row, i) in drawingRows" :key="i" class="asset-link-item" @click="openAssetUrl(row.url)">
<uni-icons type="paperclip" size="18" color="#1f4b79"></uni-icons>
<text class="asset-link-text">{{ row.name }}</text>
<uni-icons type="arrow-right" size="16" color="#94a3b8"></uni-icons>
</view>
</view>
<!-- Tab6: 操作手册 -->
<view v-else-if="currentTab === 6">
<view v-if="!manualRows.length" class="hint"></view>
<view v-for="(row, i) in manualRows" :key="i" class="asset-link-item" @click="openAssetUrl(row.url)">
<uni-icons type="paperclip" size="18" color="#1f4b79"></uni-icons>
<text class="asset-link-text">{{ row.name }}</text>
<uni-icons type="arrow-right" size="16" color="#94a3b8"></uni-icons>
</view>
</view>
<!-- Tab7: 操作视频 -->
<view v-else>
<view v-if="!videoRows.length" class="hint"></view>
<view v-for="(row, i) in videoRows" :key="i" class="video-item">
<!-- 视频封面 -->
<view class="video-cover-wrap" @click="playVideo(row.url)">
<video
:id="'video-' + i"
:src="row.url"
class="asset-video"
:title="row.name"
controls
object-fit="cover"
></video>
</view>
<!-- 文件名和下载按钮 -->
<view class="video-actions">
<text class="video-name-text">{{ row.name }}</text>
<view class="video-download" @click="downloadVideo(row.url, row.name)">
<uni-icons type="download" size="18" color="#1f4b79"></uni-icons>
<text>下载</text>
</view>
</view>
</view>
</view>
</view>
</view>
@ -256,6 +423,7 @@ const installLoading = ref(false)
const childMolds = ref([])
const childSearchCode = ref('')
const childSearchName = ref('')
const childSearchExpanded = ref(false)
const filteredChildMolds = computed(() => {
if (!childSearchCode.value.trim() && !childSearchName.value.trim()) return childMolds.value
@ -265,8 +433,58 @@ const filteredChildMolds = computed(() => {
return matchCode && matchName
})
})
// ===== Tab1 =====
const inspectionStartDate = ref('')
const inspectionEndDate = ref('')
// ===== Tab2 =====
const repairSearchCode = ref('')
const repairSearchStatus = ref('')
const repairStartDate = ref('')
const repairEndDate = ref('')
const repairSearchExpanded = ref(false)
const repairStatusOptions = [
{ label: '全部', value: '' },
{ label: '处理中', value: '0' },
{ label: '完成', value: '1' }
]
// ===== Tab3 =====
const maintainStartDate = ref('')
const maintainEndDate = ref('')
// ===== Tab4 =====
const installOperateType = ref('')
const installStartDate = ref('')
const installEndDate = ref('')
const installSearchExpanded = ref(false)
const installPageNo = ref(1)
const installPageSize = ref(10)
const installTotal = ref(0)
const installOperateOptions = [
{ label: '全部', value: '' },
{ label: '上模', value: '1' },
{ label: '下模', value: '2' }
]
const inspectionList = ref([])
const repairList = ref([])
//
const filteredRepairList = computed(() => {
const rows = Array.isArray(repairList.value) ? repairList.value : []
return rows.filter(row => {
//
const code = repairSearchCode.value.trim().toLowerCase()
if (code && !((row?.repairCode || '').toLowerCase().includes(code))) return false
//
const status = repairSearchStatus.value
if (status && String(row?.status) !== status) return false
//
if (repairStartDate.value || repairEndDate.value) {
const dateStr = formatDateTime(row?.finishDate || row?.createTime)
if (repairStartDate.value && dateStr < repairStartDate.value) return false
if (repairEndDate.value && dateStr > repairEndDate.value) return false
}
return true
})
})
const maintainList = ref([])
const installRecords = ref([])
@ -275,7 +493,10 @@ const tabList = ref([
{ name: t('moldLedger.tabInspection') },
{ name: t('moldLedger.tabRepair') },
{ name: t('moldLedger.tabMaintenance') },
{ name: t('moldLedger.tabInstall') }
{ name: t('moldLedger.tabInstall') },
{ name: '图纸' },
{ name: '操作手册' },
{ name: '操作视频' }
])
const coverImage = computed(() => parseImages(detailData.value?.images)[0] || '')
@ -283,6 +504,63 @@ const currentDeviceLabel = computed(() =>
detailValue(detailData.value?.currentDevice || detailData.value?.machineName || detailData.value?.deviceName)
)
const childMoldCount = computed(() => childMolds.value.length || detailData.value?.childMoldCount || detailData.value?.moldSize || 0)
// ===== / / =====
const drawingRows = computed(() => parseAssetRows(detailData.value?.drawings))
const manualRows = computed(() => parseAssetRows(detailData.value?.operationManual))
const videoRows = computed(() => parseAssetRows(detailData.value?.operationVideo))
function parseAssetRows(value) {
if (!value) return []
const text = String(value).trim()
// JSON
if (text.startsWith('{') || text.startsWith('[')) {
try {
const parsed = JSON.parse(text)
const list = Array.isArray(parsed) ? parsed : [parsed]
return list.map(item => {
if (item && typeof item === 'object' && item.fileUrl) {
return {
url: String(item.fileUrl),
name: item.fileName ? String(item.fileName) : getAssetName(item.fileUrl)
}
}
return null
}).filter(Boolean)
} catch { /* fall through */ }
}
// URL
return parseAssetUrls(text).map(url => ({ url, name: getAssetName(url) }))
}
function parseAssetUrls(value) {
if (!value) return []
return String(value)
.replace(/[`'"]/g, '')
.split(',')
.map(s => s.trim())
.filter(Boolean)
}
function getAssetName(url) {
const clean = String(url || '').split('?')[0]
const idx = clean.lastIndexOf('/')
if (idx === -1) return clean || '未命名文件'
try { return decodeURIComponent(clean.substring(idx + 1)) } catch { return clean.substring(idx + 1) }
}
function openAssetUrl(url) {
if (!url) return
// #ifdef H5
window.open(url, '_blank')
// #endif
// #ifdef APP-PLUS
plus.runtime.openURL(url)
// #endif
// #ifdef MP-WEIXIN
uni.setClipboardData({ data: url, success: () => uni.showToast({ title: '链接已复制', icon: 'success' }) })
// #endif
}
const statusLabel = computed(() => getDictLabel(DICT_TYPE.ERP_MOLD_STATUS, detailData.value?.status, detailValue(detailData.value?.status)))
const statusTagType = computed(() => {
const label = String(statusLabel.value || '')
@ -317,7 +595,7 @@ const maintainGroups = computed(() =>
)
const repairRecords = computed(() => {
const rows = Array.isArray(repairList.value) ? repairList.value : []
const rows = Array.isArray(filteredRepairList.value) ? filteredRepairList.value : []
return rows.map((row, index) => {
const resultMeta = formatRepairResult(row?.repairResult ?? row?.repairStatus ?? row?.result)
return {
@ -342,6 +620,101 @@ function resetChildSearch() {
childSearchName.value = ''
}
// ===== =====
const repairStatusIndex = computed(() => {
const idx = repairStatusOptions.findIndex(o => o.value === repairSearchStatus.value)
return idx >= 0 ? idx : 0
})
const installOperateIndex = computed(() => {
const idx = installOperateOptions.findIndex(o => o.value === installOperateType.value)
return idx >= 0 ? idx : 0
})
// ===== Tab1 =====
function onInspectionStartChange(e) { inspectionStartDate.value = e.detail.value; handleInspectionSearch() }
function onInspectionEndChange(e) { inspectionEndDate.value = e.detail.value; handleInspectionSearch() }
function handleInspectionSearch() {
loadedTabs.value.delete(1)
fetchInspectionRecords()
}
function resetInspectionSearch() {
inspectionStartDate.value = ''
inspectionEndDate.value = ''
handleInspectionSearch()
}
// ===== Tab2 =====
function onRepairStartChange(e) { repairStartDate.value = e.detail.value }
function onRepairEndChange(e) { repairEndDate.value = e.detail.value }
function onRepairStatusChange(e) {
const idx = e.detail.value
repairSearchStatus.value = repairStatusOptions[idx]?.value ?? ''
}
function handleRepairSearch() { /* 客户端过滤无需API请求 */ }
function resetRepairSearch() {
repairSearchCode.value = ''
repairSearchStatus.value = ''
repairStartDate.value = ''
repairEndDate.value = ''
repairSearchExpanded.value = false
}
// ===== Tab3 =====
function onMaintainStartChange(e) { maintainStartDate.value = e.detail.value; handleMaintainSearch() }
function onMaintainEndChange(e) { maintainEndDate.value = e.detail.value; handleMaintainSearch() }
function handleMaintainSearch() {
loadedTabs.value.delete(3)
fetchMaintainRecords()
}
function resetMaintainSearch() {
maintainStartDate.value = ''
maintainEndDate.value = ''
handleMaintainSearch()
}
// ===== Tab4 =====
function onInstallStartChange(e) { installStartDate.value = e.detail.value; handleInstallSearch() }
function onInstallEndChange(e) { installEndDate.value = e.detail.value; handleInstallSearch() }
function onInstallOperateChange(e) {
const idx = e.detail.value
installOperateType.value = installOperateOptions[idx]?.value ?? ''
handleInstallSearch()
}
function handleInstallSearch() {
installPageNo.value = 1
loadedTabs.value.delete(4)
fetchInstallRecords()
}
function resetInstallSearch() {
installOperateType.value = ''
installStartDate.value = ''
installEndDate.value = ''
installSearchExpanded.value = false
installPageNo.value = 1
handleInstallSearch()
}
function installPrevPage() {
if (installPageNo.value <= 1) return
installPageNo.value--
fetchInstallRecords()
}
function installNextPage() {
if (installPageNo.value >= Math.ceil(installTotal.value / installPageSize.value)) return
installPageNo.value++
fetchInstallRecords()
}
// ===== =====
function formatSearchTime(dateStr, isEnd) {
if (!dateStr) return undefined
if (isEnd) return `${dateStr} 23:59:59`
return `${dateStr} 00:00:00`
}
function formatSearchDateRange(startStr, endStr) {
if (!startStr || !endStr) return undefined
return [formatSearchTime(startStr, false), formatSearchTime(endStr, true)]
}
function refreshChildMoldsIfNeeded() {
loadedTabs.value.delete(0)
fetchChildMolds()
@ -401,6 +774,11 @@ async function loadTabData(tabIndex) {
case 4:
await fetchInstallRecords()
break
case 5:
case 6:
case 7:
// // detailData
break
default:
break
}
@ -435,7 +813,10 @@ async function fetchInspectionRecords() {
if (!brandId.value) return
inspectionLoading.value = true
try {
const res = await getMoldInspectionByMoldId(brandId.value)
const params = { moldId: brandId.value }
if (inspectionStartDate.value) params.startTime = formatSearchTime(inspectionStartDate.value, false)
if (inspectionEndDate.value) params.endTime = formatSearchTime(inspectionEndDate.value, true)
const res = await getMoldInspectionByMoldId(brandId.value, params)
inspectionList.value = normalizeListData(res)
} catch (e) {
inspectionList.value = []
@ -463,7 +844,10 @@ async function fetchMaintainRecords() {
if (!brandId.value) return
maintainLoading.value = true
try {
const res = await getMoldMaintenanceByMoldId(brandId.value)
const params = { moldId: brandId.value }
if (maintainStartDate.value) params.startTime = formatSearchTime(maintainStartDate.value, false)
if (maintainEndDate.value) params.endTime = formatSearchTime(maintainEndDate.value, true)
const res = await getMoldMaintenanceByMoldId(brandId.value, params)
maintainList.value = normalizeListData(res)
} catch (e) {
maintainList.value = []
@ -477,10 +861,25 @@ async function fetchInstallRecords() {
if (!brandId.value) return
installLoading.value = true
try {
const res = await getMoldOperatePage({ pageNo: 1, pageSize: 100, moldId: brandId.value })
installRecords.value = normalizePageData(res).list
const params = {
pageNo: installPageNo.value,
pageSize: installPageSize.value,
moldId: brandId.value
}
if (installOperateType.value) params.operateType = installOperateType.value
if (installStartDate.value || installEndDate.value) {
params.createTime = [
installStartDate.value ? formatSearchTime(installStartDate.value, false) : '',
installEndDate.value ? formatSearchTime(installEndDate.value, true) : ''
]
}
const res = await getMoldOperatePage(params)
const pageData = normalizePageData(res)
installRecords.value = pageData.list
installTotal.value = pageData.total
} catch (e) {
installRecords.value = []
installTotal.value = 0
uni.showToast({ title: t('moldLedger.installLoadFailed'), icon: 'none' })
} finally {
installLoading.value = false
@ -649,6 +1048,56 @@ function previewImages(list, current) {
uni.previewImage({ urls: list, current })
}
function playVideo(url) {
if (!url) return
//
const videoContext = uni.createVideoContext('video-0')
if (videoContext && videoContext.requestFullScreen) {
videoContext.requestFullScreen({ direction: 0 })
}
// #ifdef H5
// H5
window.open(url, '_blank')
// #endif
}
function downloadVideo(url, name) {
if (!url) return
uni.showLoading({ title: '下载中...' })
uni.downloadFile({
url,
success: (res) => {
if (res.statusCode === 200) {
// APP +
uni.saveVideoToPhotosAlbum({
filePath: res.tempFilePath,
success: () => {
uni.hideLoading()
uni.showToast({ title: '已保存到相册', icon: 'success' })
},
fail: () => {
//
// #ifdef APP-PLUS
plus.runtime.openFile(res.tempFilePath)
// #endif
uni.hideLoading()
// #ifndef APP-PLUS
uni.showToast({ title: '下载完成', icon: 'success' })
// #endif
}
})
} else {
uni.hideLoading()
uni.showToast({ title: '下载失败', icon: 'none' })
}
},
fail: () => {
uni.hideLoading()
uni.showToast({ title: '下载失败', icon: 'none' })
}
})
}
function openRepairDetail(row) {
const id = row?.id
if (id === undefined || id === null || id === '') {
@ -781,13 +1230,28 @@ function openRepairDetail(row) {
.search-bar { display: flex; flex-direction: column; gap: 12rpx; padding: 12rpx 0 16rpx; }
.search-row { display: flex; gap: 12rpx; }
.search-field { display: flex; align-items: center; gap: 8rpx; flex: 1; }
.search-field { display: flex; align-items: center; gap: 8rpx; flex: 1; margin-bottom: 12rpx; }
.search-field:last-child { margin-bottom: 0; }
.search-label { font-size: 24rpx; color: #4b5563; white-space: nowrap; flex-shrink: 0; }
.search-input { flex: 1; height: 60rpx; padding: 0 14rpx; background: #f8fafc; border: 1rpx solid #e5e7eb; border-radius: 8rpx; font-size: 24rpx; color: #374151; box-sizing: border-box; min-width: 0; }
.search-btns { display: flex; gap: 12rpx; justify-content: flex-end; }
.search-btn { flex: 1; height: 60rpx; border-radius: 8rpx; border: 1rpx solid #1f4b79; background: #1f4b79; display: flex; align-items: center; justify-content: center; gap: 4rpx; font-size: 24rpx; color: #fff; white-space: nowrap; }
.search-btn:active { opacity: 0.85; }
.search-bar.compact { gap: 8rpx; }
.compact-row { display: flex; align-items: center; gap: 8rpx; }
.search-bar.compact .compact-field { margin: 0 !important; display: flex; align-items: center; flex: 1; min-width: 0; }
.search-bar.compact .search-label { width: 100rpx; text-align: left; flex-shrink: 0; font-size: 24rpx; line-height: 60rpx; }
.search-bar.compact .search-picker,
.search-bar.compact .search-input { flex: 1; height: 60rpx; min-width: 0; }
.search-bar.compact .search-picker-value { line-height: 60rpx; }
.search-expand-area { display: flex; flex-direction: column; gap: 8rpx; }
.search-toggle { width: 52rpx; height: 52rpx; border-radius: 8rpx; background: #f1f5f9; border: 1rpx solid #e5e7eb; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.search-toggle:active { background: #e2e8f0; }
.search-icon-btn { width: 52rpx; height: 52rpx; border-radius: 8rpx; display: flex; align-items: center; justify-content: center; flex-shrink: 0; background: #f1f5f9; border: 1rpx solid #e5e7eb; }
.search-icon-btn:active { background: #e2e8f0; }
.hint {
padding: 40rpx 0;
text-align: center;
@ -1029,6 +1493,144 @@ function openRepairDetail(row) {
background: #edf2f7;
}
/* ===== 搜索栏 picker 样式 ===== */
.search-picker {
flex: 1;
height: 60rpx;
padding: 0 14rpx;
background: #f8fafc;
border: 1rpx solid #e5e7eb;
border-radius: 8rpx;
display: flex;
align-items: center;
min-width: 0;
box-sizing: border-box;
}
.search-picker-value {
font-size: 24rpx;
color: #374151;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ===== 分页 ===== */
.pagination-bar {
display: flex;
align-items: center;
justify-content: center;
gap: 20rpx;
padding: 24rpx 0 8rpx;
}
.pagination-btn {
padding: 12rpx 28rpx;
border-radius: 8rpx;
background: #1f4b79;
color: #fff;
font-size: 24rpx;
}
.pagination-btn.disabled {
background: #cbd5e1;
color: #94a3b8;
}
.pagination-info {
font-size: 24rpx;
color: #64748b;
}
/* ===== 图纸 / 操作手册 链接项 ===== */
.asset-link-item {
display: flex;
align-items: center;
gap: 16rpx;
padding: 24rpx 20rpx;
margin-bottom: 12rpx;
border-radius: 14rpx;
background: #f8fbff;
border: 1rpx solid #e8edf4;
}
.asset-link-item:last-child {
margin-bottom: 0;
}
.asset-link-item:active {
background: #eef3fa;
}
.asset-link-text {
flex: 1;
min-width: 0;
font-size: 26rpx;
color: #1f4b79;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ===== 操作视频 ===== */
.video-item {
margin-bottom: 20rpx;
border-radius: 14rpx;
background: #f8fbff;
border: 1rpx solid #e8edf4;
overflow: hidden;
}
.video-item:last-child {
margin-bottom: 0;
}
.video-cover-wrap {
position: relative;
width: 100%;
height: 360rpx;
border-radius: 14rpx 14rpx 0 0;
overflow: hidden;
background: #000;
}
.asset-video {
width: 100%;
height: 100%;
}
.video-actions {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx 20rpx;
background: #f8fbff;
border-radius: 0 0 14rpx 14rpx;
}
.video-name-text {
font-size: 24rpx;
color: #64748b;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
}
.video-download {
display: flex;
align-items: center;
gap: 6rpx;
padding: 8rpx 18rpx;
border-radius: 8rpx;
background: #e8f0fe;
font-size: 24rpx;
color: #1f4b79;
flex-shrink: 0;
}
.text-success {
color: #16a34a;
}

Loading…
Cancel
Save