黄伟杰 3 days ago
commit 96d09911c2

@ -368,7 +368,19 @@ export default {
changeTarget: 'Change Dismount Target',
confirmDismount: 'Confirm Dismount',
clickSelectDeviceFirst: 'Please select a device first',
noMoldOnDevice: 'No mold on this device'
noMoldOnDevice: 'No mold on this device',
historySuffix: ' History',
historyTitle: 'Mold Operate History',
searchPlaceholder: 'Search device/mold name',
filterAll: 'All',
filterToday: 'Today',
filterWeek: 'This Week',
historyEmpty: 'No history records',
totalPrefix: 'Total: ',
totalSuffix: '',
confirmDeleteHistory: 'Confirm delete this history record?',
operateTime: 'Operate Time',
operator: 'Operator'
},
moldInspectionItems: {
moduleName: 'Inspection Items',

@ -368,7 +368,19 @@ export default {
changeTarget: '更换下模对象',
confirmDismount: '确认下模',
clickSelectDeviceFirst: '请先选择设备',
noMoldOnDevice: '该设备暂无在机模具'
noMoldOnDevice: '该设备暂无在机模具',
historySuffix: '历史',
historyTitle: '上下模历史',
searchPlaceholder: '搜索设备/模具名称',
filterAll: '全部',
filterToday: '今天',
filterWeek: '本周',
historyEmpty: '暂无历史记录',
totalPrefix: '共 ',
totalSuffix: ' 条',
confirmDeleteHistory: '确认删除该历史记录吗?',
operateTime: '操作时间',
operator: '操作人'
},
moldInspectionItems: {
moduleName: '点检项库',

@ -610,6 +610,13 @@
"navigationStyle": "custom"
}
},
{
"path": "moldoperate/history",
"style": {
"navigationBarTitleText": "上下模历史",
"navigationStyle": "custom"
}
},
{
"path": "moldRepair/index",
"style": {

@ -33,7 +33,7 @@
</view>
<view class="device-info-row">
<text class="info-label">{{ t('moldOperate.productionLine') }}</text>
<text class="info-value">{{ textValue(device.workshopName) }}</text>
<text class="info-value">{{ getTopLineName(device.deviceLine) }}</text>
</view>
<view class="device-info-row">
<text class="info-label">{{ t('moldOperate.currentMold') }}</text>
@ -68,6 +68,7 @@ import { onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getDeviceLedgerList } from '@/api/mes/moldoperate'
import { getDeviceLineTree } from '@/api/mes/deviceLine'
const { t } = useI18n()
@ -76,6 +77,8 @@ const selectedId = ref(null)
const searchText = ref('')
const loading = ref(false)
const lineInfoMap = ref(new Map())
function textValue(v) {
if (v === 0) return '0'
if (v == null) return '-'
@ -163,13 +166,64 @@ function getCurrentMold(device) {
return staticMold === '-' ? t('moldOperate.noMoldOnDevice') : staticMold
}
function flattenLineTree(nodes, parentId) {
if (!Array.isArray(nodes)) return
for (const node of nodes) {
if (node.id != null && node.name != null) {
lineInfoMap.value.set(String(node.id), {
id: node.id,
name: node.name,
parentId: node.parentId != null ? node.parentId : (parentId || null),
parentChain: node.parentChain || ''
})
}
if (Array.isArray(node.children)) {
flattenLineTree(node.children, node.id)
}
}
}
function getTopLineName(deviceLineId) {
if (deviceLineId == null) return '-'
const node = lineInfoMap.value.get(String(deviceLineId))
if (!node) return '-'
if (node.parentChain) {
const firstId = node.parentChain.split(',')[0]?.trim()
if (firstId) {
const topNode = lineInfoMap.value.get(firstId)
if (topNode) return topNode.name
}
}
let current = node
const visited = new Set()
while (current.parentId != null && current.parentId > 0 && !visited.has(current.id)) {
visited.add(current.id)
const parent = lineInfoMap.value.get(String(current.parentId))
if (!parent) break
current = parent
}
return current.name || '-'
}
async function loadLineTree() {
if (lineInfoMap.value.size > 0) return
try {
const res = await getDeviceLineTree()
const tree = (res && res.data !== undefined) ? res.data : res
const nodes = Array.isArray(tree) ? tree : (tree?.list || tree?.children || [])
flattenLineTree(nodes)
} catch (e) {
console.error('load line tree error', e)
}
}
const filteredList = computed(() => {
const keyword = searchText.value.trim().toLowerCase()
if (!keyword) return deviceList.value
return deviceList.value.filter((d) => {
return (d.deviceName || '').toLowerCase().includes(keyword) ||
(d.deviceCode || '').toLowerCase().includes(keyword) ||
(d.workshopName || '').toLowerCase().includes(keyword)
(getTopLineName(d.deviceLine) || '').toLowerCase().includes(keyword)
})
})
@ -203,13 +257,19 @@ function handleConfirm() {
return
}
const device = deviceList.value.find((d) => d.id === selectedId.value)
if (device) {
const lineName = getTopLineName(device.deviceLine)
if (lineName && lineName !== '-') {
device.workshopName = lineName
}
}
// globalData onShow
getApp().globalData._deviceSelectResult = device || null
uni.navigateBack()
}
onShow(async () => {
await loadDevices()
await Promise.allSettled([loadDevices(), loadLineTree()])
})
</script>

@ -1,6 +1,10 @@
<template>
<view class="page-container">
<NavBar :title="t('moldOperate.tabDown')" />
<NavBar :title="t('moldOperate.tabDown')">
<template #right>
<image class="nav-right-icon" src="/static/logo/history.png" mode="aspectFit" @click="goToHistory" />
</template>
</NavBar>
<!-- 操作按钮区 -->
<view class="action-row">
@ -38,7 +42,7 @@
<view class="grid-row">
<view class="grid-cell">
<text class="grid-label">{{ t('moldOperate.productionLine') }}</text>
<text class="grid-value">{{ textValue(selectedDevice.workshopName) }}</text>
<text class="grid-value">{{ getTopLineName(selectedDevice.deviceLine) }}</text>
</view>
<view class="grid-cell">
<text class="grid-label">{{ t('moldOperate.deviceStatus') }}</text>
@ -140,9 +144,70 @@ import { onShow } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import NavBar from '@/components/common/NavBar.vue'
import { getLowerMoldList, getDeviceLedgerList, createMoldOperate } from '@/api/mes/moldoperate'
import { getDeviceLineTree } from '@/api/mes/deviceLine'
const { t } = useI18n()
const lineInfoMap = ref(new Map()) // deviceLine id { name, parentId, parentChain }
// 线
function flattenLineTree(nodes, parentId) {
if (!Array.isArray(nodes)) return
for (const node of nodes) {
if (node.id != null && node.name != null) {
lineInfoMap.value.set(String(node.id), {
id: node.id,
name: node.name,
parentId: node.parentId != null ? node.parentId : (parentId || null),
parentChain: node.parentChain || ''
})
}
if (Array.isArray(node.children)) {
flattenLineTree(node.children, node.id)
}
}
}
// 线线 fillTopCategoryInfo
function getTopLineName(deviceLineId) {
if (deviceLineId == null) return '-'
const node = lineInfoMap.value.get(String(deviceLineId))
if (!node) return String(deviceLineId)
// 1 parentChain ID
if (node.parentChain) {
const firstId = node.parentChain.split(',')[0]?.trim()
if (firstId) {
const topNode = lineInfoMap.value.get(firstId)
if (topNode) return topNode.name
}
}
// 2 parentId
let current = node
const visited = new Set()
while (current.parentId != null && current.parentId > 0 && !visited.has(current.id)) {
visited.add(current.id)
const parent = lineInfoMap.value.get(String(current.parentId))
if (!parent) break
current = parent
}
return current.name || String(deviceLineId)
}
// 线
async function loadLineTree() {
if (lineInfoMap.value.size > 0) return
try {
const res = await getDeviceLineTree()
const tree = (res && res.data !== undefined) ? res.data : res
const nodes = Array.isArray(tree) ? tree : (tree?.list || tree?.children || [])
flattenLineTree(nodes)
} catch (e) {
console.error('load line tree error', e)
}
}
// ---- ----
const selectedDevice = ref({})
const deviceOptions = ref([])
@ -376,6 +441,10 @@ function handleSelectDeviceFirst() {
openDevicePicker()
}
function goToHistory() {
uni.navigateTo({ url: '/pages_function/pages/moldoperate/history?type=down' })
}
// ---- ----
function validForm() {
if (!selectedDevice.value?.id) {
@ -392,10 +461,13 @@ function validForm() {
async function handleConfirm() {
if (!validForm()) return
try {
const device = selectedDevice.value
const payload = {
operateType: '2',
deviceId: String(selectedDevice.value.id),
moldId: String(selectedMold.value.id)
deviceId: String(device.id),
moldId: String(selectedMold.value.id),
lineId: device.deviceLine != null ? String(device.deviceLine) : undefined,
lineName: device.deviceLine != null ? getTopLineName(device.deviceLine) : (device.lineName || undefined)
}
console.log('[下模] 提交参数 =', JSON.stringify(payload))
await createMoldOperate(payload)
@ -420,7 +492,7 @@ async function handleConfirm() {
}
onShow(async () => {
await Promise.allSettled([loadDevices()])
await Promise.allSettled([loadDevices(), loadLineTree()])
// globalData
const device = getApp().globalData._deviceSelectResult
if (device) {
@ -431,6 +503,11 @@ onShow(async () => {
</script>
<style lang="scss" scoped>
.nav-right-icon {
width: 40rpx;
height: 40rpx;
}
.page-container {
min-height: 100vh;
background: #f5f6f8;

@ -0,0 +1,739 @@
<template>
<view class="page-container">
<!-- 顶部导航栏 -->
<view class="custom-nav">
<view class="nav-back" @click="goBack">
<text class="back-icon">&lt;</text>
</view>
<text class="nav-title">{{ pageType ? (pageType === 'up' ? t('moldOperate.tabUp') : t('moldOperate.tabDown')) + t('moldOperate.historySuffix') : t('moldOperate.historyTitle') }}</text>
<view class="nav-placeholder"></view>
</view>
<!-- Tab 切换路由指定 type 时隐藏 -->
<view v-if="!pageType" class="tab-bar">
<view
class="tab-item"
:class="{ active: activeTab === 'up' }"
@click="switchTab('up')"
>
<text class="tab-text">{{ t('moldOperate.tabUp') }}</text>
<view v-if="activeTab === 'up'" class="tab-line"></view>
</view>
<view
class="tab-item"
:class="{ active: activeTab === 'down' }"
@click="switchTab('down')"
>
<text class="tab-text">{{ t('moldOperate.tabDown') }}</text>
<view v-if="activeTab === 'down'" class="tab-line"></view>
</view>
</view>
<!-- 搜索区域 -->
<view class="search-bar">
<view class="search-input-wrap">
<input
v-model="searchKeyword"
class="search-input"
:placeholder="t('moldOperate.searchPlaceholder')"
placeholder-class="search-placeholder"
confirm-type="search"
@confirm="handleSearch"
/>
</view>
<view class="search-select" @click="toggleFilter">
<text class="select-text">{{ filterLabel }}</text>
<text class="select-arrow">&#9662;</text>
</view>
<view class="search-btn reset" @click="handleReset">
<text>{{ t('functionCommon.reset') }}</text>
</view>
<view class="search-btn filter" @click="toggleFilter">
<text class="filter-icon">&#9776;</text>
</view>
</view>
<!-- 筛选条件弹层 -->
<view v-if="showFilter" class="filter-dropdown">
<view
v-for="opt in filterOptions"
:key="opt.key"
class="filter-option"
:class="{ active: filterType === opt.key }"
@click="selectFilter(opt.key)"
>
<text>{{ opt.label }}</text>
<text v-if="filterType === opt.key" class="check-mark">&#10003;</text>
</view>
</view>
<!-- 列表内容 -->
<scroll-view scroll-y class="list-scroll" :scroll-top="scrollTop" :style="{ height: pageType ? 'calc(100vh - 88rpx - 98rpx)' : 'calc(100vh - 88rpx - 80rpx - 98rpx)' }">
<template v-if="displayList.length > 0">
<view
v-for="(item, index) in displayList"
:key="item.id || index"
class="history-card"
>
<!-- 顶部模具名称 + 标签 -->
<view class="card-top">
<text class="card-title">{{ item.moldName || '-' }}</text>
<view class="type-tag" :class="(item.operateType === '1' || item.operateType === 1) ? 'type-up' : 'type-down'">
<text>{{ (item.operateType === '1' || item.operateType === 1) ? t('moldOperate.tabUp') : t('moldOperate.tabDown') }}</text>
</view>
</view>
<!-- 信息行 Web 端表格列对齐 -->
<view class="info-row">
<text class="info-label">{{ t('moldOperate.deviceName') }}</text>
<text class="info-value">{{ item.deviceName || getDeviceName(item.deviceId) || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldOperate.productionLine') }}</text>
<text class="info-value">{{ item.lineName || getTopLineName(item.lineId) || getLineNameByDeviceId(item.deviceId) || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldOperate.operator') }}</text>
<text class="info-value">{{ item.creatorName || item.operator || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldOperate.remark') }}</text>
<text class="info-value">{{ item.remark || '-' }}</text>
</view>
<view class="info-row">
<text class="info-label">{{ t('moldOperate.operateTime') }}</text>
<text class="info-value">{{ formatDateTime(item.operateTime || item.createTime) }}</text>
</view>
<!-- 右下角删除 -->
<view class="card-footer">
<view class="delete-wrap" @click="handleDelete(item)">
<text class="delete-icon">&#128465;</text>
</view>
</view>
</view>
</template>
<!-- 空状态 -->
<view v-else class="empty-wrap">
<text class="empty-text">{{ loading ? t('functionCommon.loading') : t('moldOperate.historyEmpty') }}</text>
</view>
<!-- 分页 -->
<view v-if="displayList.length > 0" class="pagination-bar">
<text class="pagination-total">{{ t('moldOperate.totalPrefix') }}{{ total }}{{ t('moldOperate.totalSuffix') }}</text>
<view class="pagination-ctrl">
<text
class="page-btn"
:class="{ disabled: pageNo <= 1 }"
@click="changePage(pageNo - 1)"
>&lt;</text>
<text class="page-current">{{ pageNo }}</text>
<text
class="page-btn"
:class="{ disabled: pageNo >= totalPages }"
@click="changePage(pageNo + 1)"
>&gt;</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { onShow, onLoad } from '@dcloudio/uni-app'
import { useI18n } from 'vue-i18n'
import { getMoldOperatePage, deleteMoldOperate, getDeviceLedgerList } from '@/api/mes/moldoperate'
import { getDeviceLineTree } from '@/api/mes/deviceLine'
const { t } = useI18n()
const pageType = ref('')
const activeTab = ref('up')
const searchKeyword = ref('')
const filterType = ref('all')
const showFilter = ref(false)
const allList = ref([])
const loading = ref(false)
const pageNo = ref(1)
const pageSize = ref(10)
const scrollTop = ref(0)
const lineInfoMap = ref(new Map())
const deviceMap = ref(new Map())
const total = computed(() => filteredList.value.length)
const totalPages = computed(() => Math.ceil(total.value / pageSize.value) || 1)
const filterLabel = computed(() => {
if (filterType.value === 'all') return t('moldOperate.filterAll')
if (filterType.value === 'today') return t('moldOperate.filterToday')
if (filterType.value === 'week') return t('moldOperate.filterWeek')
return t('moldOperate.filterAll')
})
const filterOptions = [
{ key: 'all', label: t('moldOperate.filterAll') },
{ key: 'today', label: t('moldOperate.filterToday') },
{ key: 'week', label: t('moldOperate.filterWeek') }
]
const filteredList = computed(() => {
let list = allList.value
if (filterType.value === 'today') {
const today = new Date().toDateString()
list = list.filter(item => {
const d = item.operateTime || item.createTime
return d && new Date(d).toDateString() === today
})
} else if (filterType.value === 'week') {
const now = new Date()
const weekAgo = new Date(now.getTime() - 7 * 24 * 3600 * 1000)
list = list.filter(item => {
const d = item.operateTime || item.createTime
return d && new Date(d) >= weekAgo
})
}
if (searchKeyword.value.trim()) {
const kw = searchKeyword.value.trim().toLowerCase()
list = list.filter(item => {
return (item.deviceName || '').toLowerCase().includes(kw) ||
(item.moldCode || '').toLowerCase().includes(kw) ||
(item.moldName || '').toLowerCase().includes(kw) ||
(item.operator || '').toLowerCase().includes(kw) ||
(item.creatorName || '').toLowerCase().includes(kw)
})
}
return list
})
const displayList = computed(() => {
const start = (pageNo.value - 1) * pageSize.value
return filteredList.value.slice(start, start + pageSize.value)
})
function getDeviceName(deviceId) {
if (!deviceId) return '-'
const d = deviceMap.value.get(String(deviceId))
return d?.deviceName || '-'
}
function getLineNameByDeviceId(deviceId) {
if (!deviceId) return null
const d = deviceMap.value.get(String(deviceId))
if (!d) return null
if (d.deviceLine != null) {
return getTopLineName(d.deviceLine)
}
return d.workshopName || null
}
function flattenLineTree(nodes, parentId) {
if (!Array.isArray(nodes)) return
for (const node of nodes) {
if (node.id != null && node.name != null) {
lineInfoMap.value.set(String(node.id), {
id: node.id,
name: node.name,
parentId: node.parentId != null ? node.parentId : (parentId || null),
parentChain: node.parentChain || ''
})
}
if (Array.isArray(node.children)) {
flattenLineTree(node.children, node.id)
}
}
}
function getTopLineName(lineId) {
if (lineId == null) return '-'
const node = lineInfoMap.value.get(String(lineId))
if (!node) return '-'
if (node.parentChain) {
const firstId = node.parentChain.split(',')[0]?.trim()
if (firstId) {
const topNode = lineInfoMap.value.get(firstId)
if (topNode) return topNode.name
}
}
let current = node
const visited = new Set()
while (current.parentId != null && current.parentId > 0 && !visited.has(current.id)) {
visited.add(current.id)
const parent = lineInfoMap.value.get(String(current.parentId))
if (!parent) break
current = parent
}
return current.name || String(lineId)
}
async function loadLineTree() {
if (lineInfoMap.value.size > 0) return
try {
const res = await getDeviceLineTree()
const tree = (res && res.data !== undefined) ? res.data : res
const nodes = Array.isArray(tree) ? tree : (tree?.list || tree?.children || [])
flattenLineTree(nodes)
} catch (e) {
console.error('load line tree error', e)
}
}
async function loadDevices() {
if (deviceMap.value.size > 0) return
try {
const res = await getDeviceLedgerList({ pageNo: 1, pageSize: 99 })
const root = res && res.data !== undefined ? res.data : res
const data = Array.isArray(root)
? root
: Array.isArray(root?.list) ? root.list
: Array.isArray(root?.records) ? root.records
: []
data.forEach(d => {
if (d.id != null) deviceMap.value.set(String(d.id), d)
})
} catch (e) {
console.error('load devices error', e)
}
}
async function fetchAll() {
if (loading.value) return
loading.value = true
try {
const operateType = activeTab.value === 'up' ? '1' : '2'
let page = 1
const batchSize = 99
const all = []
while (true) {
const res = await getMoldOperatePage({ pageNo: page, pageSize: batchSize, operateType })
const root = res && res.data !== undefined ? res.data : res
const rows = Array.isArray(root)
? root
: Array.isArray(root?.list) ? root.list
: Array.isArray(root?.rows) ? root.rows
: Array.isArray(root?.records) ? root.records
: []
if (rows.length === 0) break
all.push(...rows)
if (rows.length < batchSize) break
page++
if (page > 10) break
}
allList.value = all
} catch (e) {
console.error('fetch history error', e)
uni.showToast({ title: t('functionCommon.loadFailed'), icon: 'none' })
} finally {
loading.value = false
}
}
function switchTab(tab) {
activeTab.value = tab
pageNo.value = 1
searchKeyword.value = ''
filterType.value = 'all'
fetchAll()
}
function toggleFilter() {
showFilter.value = !showFilter.value
}
function selectFilter(key) {
filterType.value = key
showFilter.value = false
pageNo.value = 1
}
function handleSearch() {
pageNo.value = 1
}
function handleReset() {
searchKeyword.value = ''
filterType.value = 'all'
pageNo.value = 1
}
function changePage(p) {
if (p < 1 || p > totalPages.value) return
pageNo.value = p
scrollTop.value = scrollTop.value === 0 ? 1 : 0
}
function handleDelete(item) {
if (!item.id) return
uni.showModal({
title: t('functionCommon.confirmTitle'),
content: t('moldOperate.confirmDeleteHistory'),
confirmColor: '#dc2626',
success: async (res) => {
if (res.confirm) {
try {
await deleteMoldOperate(item.id)
uni.showToast({ title: t('functionCommon.deleteSuccess'), icon: 'success' })
allList.value = allList.value.filter(i => i.id !== item.id)
} catch (e) {
console.error('delete history error', e)
uni.showToast({ title: t('functionCommon.deleteFailed'), icon: 'none' })
}
}
}
})
}
function goBack() {
uni.navigateBack({ fail: () => uni.switchTab({ url: '/pages/index/index' }) })
}
function formatDateTime(value) {
if (!value) return '-'
if (Array.isArray(value) && value.length >= 3) {
const [year, month, day, hour = 0, minute = 0, second = 0] = value
const pad = (num) => String(num).padStart(2, '0')
return `${year}-${pad(month)}-${pad(day)} ${pad(hour)}:${pad(minute)}:${pad(second)}`
}
const date = new Date(value)
if (Number.isNaN(date.getTime())) return String(value)
const pad = (num) => String(num).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
watch(searchKeyword, () => {
pageNo.value = 1
})
onLoad((options) => {
if (options && options.type) {
pageType.value = options.type
activeTab.value = options.type
}
})
onShow(async () => {
await Promise.allSettled([fetchAll(), loadDevices(), loadLineTree()])
})
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background: #f5f6f8;
}
/* ====== 自定义导航栏 ====== */
.custom-nav {
display: flex;
align-items: center;
justify-content: space-between;
height: 88rpx;
padding: 0 24rpx;
background: #1a365d;
color: #fff;
.nav-back {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
font-size: 36rpx;
font-weight: bold;
}
.nav-title {
font-size: 34rpx;
font-weight: 600;
max-width: 60%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.nav-placeholder {
width: 60rpx;
}
}
/* ====== Tab 切换 ====== */
.tab-bar {
display: flex;
background: #fff;
border-bottom: 1rpx solid #eee;
.tab-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx 0;
position: relative;
.tab-text {
font-size: 28rpx;
color: #666;
}
&.active .tab-text {
color: #2563eb;
font-weight: 600;
}
.tab-line {
position: absolute;
bottom: 0;
width: 48rpx;
height: 4rpx;
background: #2563eb;
border-radius: 2rpx;
}
}
}
/* ====== 搜索区域 ====== */
.search-bar {
display: flex;
align-items: center;
padding: 12rpx 16rpx;
background: #fff;
gap: 8rpx;
.search-input-wrap {
flex: 1;
height: 64rpx;
background: #f5f6f8;
border-radius: 32rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
}
.search-input {
flex: 1;
font-size: 26rpx;
height: 100%;
}
.search-placeholder {
color: #999;
}
.search-select {
display: flex;
align-items: center;
padding: 0 16rpx;
height: 64rpx;
border-radius: 32rpx;
background: #f5f6f8;
gap: 4rpx;
}
.select-text {
font-size: 24rpx;
color: #666;
}
.select-arrow {
font-size: 18rpx;
color: #999;
}
.search-btn {
height: 64rpx;
line-height: 64rpx;
padding: 0 20rpx;
border-radius: 32rpx;
font-size: 24rpx;
&.reset {
background: #fff;
color: #666;
border: 1rpx solid #ddd;
}
&.filter {
background: #2563eb;
color: #fff;
.filter-icon {
font-size: 28rpx;
}
}
}
}
/* ====== 筛选下拉 ====== */
.filter-dropdown {
position: absolute;
top: 176rpx;
right: 16rpx;
background: #fff;
border-radius: 8rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.12);
z-index: 99;
overflow: hidden;
.filter-option {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 32rpx;
font-size: 26rpx;
color: #333;
min-width: 160rpx;
&.active {
color: #2563eb;
background: #f0f5ff;
font-weight: 500;
}
.check-mark {
color: #2563eb;
font-size: 24rpx;
}
}
}
/* ====== 列表 ====== */
.list-scroll {
padding: 16rpx 16rpx 32rpx;
}
.history-card {
background: #fff;
border-radius: 12rpx;
margin-bottom: 16rpx;
padding: 16rpx 24rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
.card-top {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10rpx;
.card-title {
font-size: 30rpx;
font-weight: 700;
color: #1a365d;
flex: 1;
}
.type-tag {
padding: 2rpx 10rpx;
border-radius: 6rpx;
font-size: 20rpx;
color: #fff;
flex-shrink: 0;
&.type-up {
background: #f97316;
}
&.type-down {
background: #f97316;
}
}
}
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4rpx 0;
.info-label {
font-size: 22rpx;
color: #999;
flex-shrink: 0;
}
.info-value {
font-size: 22rpx;
color: #333;
text-align: right;
flex: 1;
margin-left: 16rpx;
word-break: break-all;
}
}
.card-footer {
display: flex;
justify-content: flex-end;
margin-top: 6rpx;
.delete-wrap {
padding: 6rpx;
.delete-icon {
font-size: 28rpx;
color: #dc2626;
}
}
}
}
.empty-wrap {
display: flex;
align-items: center;
justify-content: center;
padding: 120rpx 0;
.empty-text {
font-size: 28rpx;
color: #999;
}
}
/* ====== 分页 ====== */
.pagination-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20rpx 0;
.pagination-total {
font-size: 24rpx;
color: #999;
}
.pagination-ctrl {
display: flex;
align-items: center;
gap: 12rpx;
.page-btn {
width: 56rpx;
height: 56rpx;
line-height: 56rpx;
text-align: center;
background: #fff;
border-radius: 8rpx;
font-size: 28rpx;
color: #333;
border: 1rpx solid #ddd;
&.disabled {
color: #ccc;
background: #f5f5f5;
}
}
.page-current {
font-size: 28rpx;
color: #333;
min-width: 40rpx;
text-align: center;
}
}
}
</style>

@ -6,7 +6,7 @@
<text class="back-icon">&lt;</text>
</view>
<text class="nav-title">{{ t('moldOperate.tabUp') }}</text>
<view class="nav-placeholder"></view>
<image class="nav-right-icon" src="/static/logo/history.png" mode="aspectFit" @click="goToHistory" />
</view>
<!-- ========== 上模 ========== -->
@ -279,7 +279,9 @@ async function handleConfirmMount() {
const payload = {
operateType: '1',
deviceId: String(selectedDevice.value.id),
moldId: moldIds.length === 1 ? String(moldIds[0]) : moldIds.map(String).join(',')
moldId: moldIds.length === 1 ? String(moldIds[0]) : moldIds.map(String).join(','),
lineName: selectedDevice.value.workshopName || '',
lineId: selectedDevice.value.deviceLine || ''
}
console.log('=== 上模提交参数 ===', JSON.stringify(payload))
console.log('=== deviceId type:', typeof payload.deviceId, 'value:', payload.deviceId)
@ -348,6 +350,10 @@ function goBack() {
uni.navigateBack({ fail: () => uni.switchTab({ url: '/pages/index/index' }) })
}
function goToHistory() {
uni.navigateTo({ url: '/pages_function/pages/moldoperate/history?type=up' })
}
onShow(async () => {
await Promise.allSettled([loadDevices()])
// globalData
@ -400,8 +406,9 @@ onShow(async () => {
font-weight: 600;
}
.nav-placeholder {
width: 60rpx;
.nav-right-icon {
width: 40rpx;
height: 40rpx;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Loading…
Cancel
Save