feat:模具扫码/详情对接接口

master
黄伟杰 1 month ago
parent f181fa9986
commit ec7962d050

@ -1,13 +1,16 @@
<script>
import { initAllDict } from '@/utils/dict'
import { getToken } from '@/utils/auth'
export default {
onLaunch: function () {
console.log('App Launch')
if (getToken()) {
initAllDict().catch(() => {})
}
},
onShow: function () {
console.log('App Show')
},
onHide: function () {
console.log('App Hide')
}
}
</script>

@ -0,0 +1,34 @@
import request from '@/utils/request'
export function getMoldDetail(id) {
return request({
url: '/admin-api/erp/mold-brand/mold/get',
method: 'get',
params: { id }
})
}
export function getMoldInspectionByMoldId(moldId, params = {}) {
return request({
url: '/admin-api/mes/mold-ticket-management/getInspectionByMoldId',
method: 'get',
params: { moldId, ...params }
})
}
export function getMoldMaintenanceByMoldId(moldId, params = {}) {
return request({
url: '/admin-api/mes/mold-ticket-management/getMaintenanceByMoldId',
method: 'get',
params: { moldId, ...params }
})
}
export function getMoldRepairListByMoldId(moldId, params = {}) {
return request({
url: '/admin-api/mes/mold-repair/getRepairListByMoldId',
method: 'get',
params: { moldId, ...params }
})
}

@ -50,6 +50,13 @@ export function delData(dictCode) {
method: 'delete'
})
}
export function getSimpleDictList() {
return request({
url: '/admin-api/system/dict-data/simple-list',
method: 'get'
})
}
//
export const processTypes = [
{text: '制浆', value: 'zhijiang'}, {text: '成型', value: 'chengxing'},
@ -72,4 +79,4 @@ export const feedingTypes = [
export function findTextByValue(enums,value){
const foundItem = enums.find(item => item.value === value);
return foundItem ? foundItem.text : null;
}
}

@ -7,10 +7,6 @@
</view>
<view class="header-content">
<text class="header-title">模具详情</text>
<text class="header-code">{{ moldData.code }}</text>
</view>
<view class="status-badge" :class="'status-' + moldData.statusType">
<text>{{ moldData.status }}</text>
</view>
</view>
@ -20,60 +16,183 @@
<view class="info-list">
<view class="info-row">
<text class="info-label">模具名称</text>
<text class="info-value">{{ moldData.name }}</text>
<text class="info-value">{{ getDetailField('name') }}</text>
</view>
<view class="info-row">
<text class="info-label">模具类型</text>
<text class="info-value">{{ moldData.type }}</text>
<text class="info-label">模具编号</text>
<text class="info-value">{{ getDetailField('code') }}</text>
</view>
<view class="info-row">
<text class="info-label">规格型号</text>
<text class="info-value">{{ moldData.spec }}</text>
<text class="info-label">模具状态</text>
<u-tag :text="statusLabel" :type="statusTagType" size="mini" />
</view>
<view class="info-row">
<text class="info-label">所属产线</text>
<text class="info-value">{{ moldData.lineName }}</text>
<text class="info-label">模具型号</text>
<text class="info-value">{{ getDetailField('brandName') }}</text>
</view>
<view class="info-row">
<text class="info-label">存放位置</text>
<text class="info-value">{{ moldData.location }}</text>
<text class="info-label">模具规格</text>
<text class="info-value">{{ getDetailField('moldType') }}</text>
</view>
</view>
</view>
<view class="info-card">
<view class="card-title">使用信息</view>
<view class="info-list">
<view class="info-row">
<text class="info-label">累计产量</text>
<text class="info-value highlight">{{ moldData.totalOutput }}</text>
<text class="info-label">工序</text>
<text class="info-value">{{ getDetailField('orgType') }}</text>
</view>
<view class="info-row">
<text class="info-label">使用寿命</text>
<text class="info-value">{{ moldData.lifeSpan }}</text>
<text class="info-label">模穴数</text>
<text class="info-value">{{ getDetailField('moldSize') }}</text>
</view>
<view class="info-row">
<text class="info-label">上次保养</text>
<text class="info-value">{{ moldData.lastMaintenance }}</text>
<text class="info-label">使用次数/</text>
<text class="info-value">{{ getDetailField('useTime') }}</text>
</view>
<view class="info-row">
<text class="info-label">下次保养</text>
<text class="info-value warning">{{ moldData.nextMaintenance }}</text>
<text class="info-label">使用设备</text>
<text class="info-value">{{ machineLabel }}</text>
</view>
<view class="info-row">
<text class="info-label">入库日期</text>
<text class="info-value">{{ inTimeLabel }}</text>
</view>
<view class="info-row">
<text class="info-label">是否启用</text>
<text class="info-value">{{ enableLabel }}</text>
</view>
<view class="info-row">
<text class="info-label">备注</text>
<text class="info-value">{{ getDetailField('remark') }}</text>
</view>
</view>
</view>
<view class="info-card">
<view class="card-title">维护记录</view>
<view class="record-list">
<view v-for="(record, index) in maintenanceRecords" :key="index" class="record-item">
<view class="record-dot"></view>
<view class="record-content">
<text class="record-title">{{ record.title }}</text>
<text class="record-time">{{ record.time }}</text>
<view class="card-title">履历</view>
<view class="tabs-box">
<u-tabs activeColor="#1a3a5c" :list="tabList" :current="currentTab" :is-scroll="false"
@change="handleTabChange" />
</view>
<view>
<view v-if="currentTab === 0">
<view v-if="!inspectionGroups.length" class="empty"></view>
<view v-for="group in inspectionGroups" :key="group.key" class="history-group">
<view class="history-group-head">
<text class="history-group-time">[{{ group.time }}]</text>
<text class="history-group-operator">操作人: {{ group.operator }}</text>
</view>
<view v-for="item in group.items" :key="item.key" class="history-item">
<view class="history-item-head">
<text class="result-badge" :class="'result-' + item.resultType">{{ item.resultLabel }}</text>
<text class="history-item-name">{{ item.name }}</text>
</view>
<view class="history-item-body">
<view class="history-row">
<text class="history-label">点检方式</text>
<text class="history-value">{{ detailValue(item.method) }}</text>
</view>
<view class="history-row">
<text class="history-label">判定标准</text>
<text class="history-value">{{ detailValue(item.criteria) }}</text>
</view>
<view class="history-row">
<text class="history-label">点检时间</text>
<text class="history-value">{{ detailValue(item.taskTimeLabel) }}</text>
</view>
<view class="history-row">
<text class="history-label">创建时间</text>
<text class="history-value">{{ detailValue(item.createTimeLabel) }}</text>
</view>
<view class="history-row">
<text class="history-label">备注</text>
<text class="history-value">{{ detailValue(item.remark) }}</text>
</view>
<view v-if="item.images && item.images.length" class="history-images">
<image v-for="img in item.images" :key="img" class="history-image" :src="img" mode="aspectFill"
@click="previewImages(item.images, img)" />
</view>
</view>
</view>
</view>
</view>
<view v-else-if="currentTab === 1">
<view v-if="!maintainGroups.length" class="empty"></view>
<view v-for="group in maintainGroups" :key="group.key" class="history-group">
<view class="history-group-head">
<text class="history-group-time">[{{ group.time }}]</text>
<text class="history-group-operator">操作人: {{ group.operator }}</text>
</view>
<view v-for="item in group.items" :key="item.key" class="history-item">
<view class="history-item-head">
<text class="result-badge" :class="'result-' + item.resultType">{{ item.resultLabel }}</text>
<text class="history-item-name">{{ item.name }}</text>
</view>
<view class="history-item-body">
<view class="history-row">
<text class="history-label">保养方式</text>
<text class="history-value">{{ detailValue(item.method) }}</text>
</view>
<view class="history-row">
<text class="history-label">判定标准</text>
<text class="history-value">{{ detailValue(item.criteria) }}</text>
</view>
<view class="history-row">
<text class="history-label">保养时间</text>
<text class="history-value">{{ detailValue(item.taskTimeLabel) }}</text>
</view>
<view class="history-row">
<text class="history-label">创建时间</text>
<text class="history-value">{{ detailValue(item.createTimeLabel) }}</text>
</view>
<view class="history-row">
<text class="history-label">备注</text>
<text class="history-value">{{ detailValue(item.remark) }}</text>
</view>
<view v-if="item.images && item.images.length" class="history-images">
<image v-for="img in item.images" :key="img" class="history-image" :src="img" mode="aspectFill"
@click="previewImages(item.images, img)" />
</view>
</view>
</view>
</view>
<view class="record-type" :class="'type-' + record.type">
<text>{{ record.typeText }}</text>
</view>
<view v-else>
<view v-if="!repairGroups.length" class="empty"></view>
<view v-for="group in repairGroups" :key="group.key" class="repair-group">
<view class="repair-group-head">
<text class="repair-group-name">{{ group.name }}</text>
<text class="repair-group-meta">{{ group.items.length }}</text>
</view>
<view v-for="row in group.items" :key="row.key" class="repair-item">
<view class="repair-item-head">
<text class="repair-tag">{{ detailValue(row.subjectCode) }}</text>
<text class="repair-title">{{ detailValue(row.subjectName) }}</text>
</view>
<view class="repair-item-body">
<view class="history-row">
<text class="history-label">项目内容</text>
<text class="history-value">{{ detailValue(row.subjectContent) }}</text>
</view>
<view class="history-row">
<text class="history-label">维修结果</text>
<text class="history-value">
<text class="result-badge" :class="'result-' + row.resultType">{{ row.resultLabel }}</text>
</text>
</view>
<view class="history-row">
<text class="history-label">备注</text>
<text class="history-value">{{ detailValue(row.remark) }}</text>
</view>
<view class="history-row">
<text class="history-label">完成日期</text>
<text class="history-value">{{ detailValue(row.finishDateLabel) }}</text>
</view>
<view v-if="row.images && row.images.length" class="history-images">
<image v-for="img in row.images" :key="img" class="history-image" :src="img" mode="aspectFill"
@click="previewImages(row.images, img)" />
</view>
</view>
</view>
</view>
</view>
</view>
@ -83,42 +202,287 @@
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
const moldData = reactive({
code: '',
name: '汽车外壳注塑模具',
type: '注塑模具',
spec: 'MJ-2024-A001',
lineName: '一号生产线',
location: 'A区-03货架-02层',
status: '正常',
statusType: 'normal',
totalOutput: '125,680 件',
lifeSpan: '85%',
lastMaintenance: '2024-03-01',
nextMaintenance: '2024-04-01'
});
import { ref, computed, onMounted } from 'vue'
import {
getMoldDetail,
getMoldInspectionByMoldId,
getMoldMaintenanceByMoldId,
getMoldRepairListByMoldId
} from '@/api/mes/mold'
import { getDictLabel, initAllDict } from '@/utils/dict'
const loading = ref(false)
const moldId = ref(undefined)
const detailData = ref(null)
const inspectionList = ref([])
const maintainList = ref([])
const repairList = ref([])
const tabList = ref([{ name: '点检履历' }, { name: '保养履历' }, { name: '维修履历' }])
const currentTab = ref(0)
function get(obj, key) {
if (!obj) return undefined
return obj[key]
}
function getDetailField(field) {
const d = detailData.value
return detailValue(d ? d[field] : undefined)
}
const statusMeta = computed(() => {
const d = detailData.value
const raw = d ? d.status : undefined
const label = getDictLabel('erp_mold_status', raw, detailValue(raw))
return formatStatus(label)
})
const statusLabel = computed(() => statusMeta.value.label)
const statusType = computed(() => statusMeta.value.type)
const statusTagType = computed(() => {
if (statusType.value === 'error') return 'error'
if (statusType.value === 'warning') return 'warning'
return 'success'
})
const machineLabel = computed(() => {
const d = detailData.value
const v = d ? d.machineName || d.machineId : undefined
return detailValue(v)
})
const inTimeLabel = computed(() => {
const d = detailData.value
return formatDateOnly(d ? d.inTime : undefined)
})
const enableLabel = computed(() => {
const d = detailData.value
return formatEnable(d ? d.isEnable : undefined)
})
const inspectionGroups = computed(() =>
buildStepGroups(inspectionList.value, {
timeFieldCandidates: ['taskTime', 'inspectionTime', 'createTime'],
nameFieldCandidates: ['inspectionItemName', 'name', 'itemName'],
resultFieldCandidates: ['inspectionResult', 'result'],
methodFieldCandidates: ['inspectionMethod', 'method'],
criteriaFieldCandidates: ['judgmentCriteria', 'criteria'],
imagesFieldCandidates: ['images'],
remarkFieldCandidates: ['remark']
})
)
const maintainGroups = computed(() =>
buildStepGroups(maintainList.value, {
timeFieldCandidates: ['taskTime', 'inspectionTime', 'createTime'],
nameFieldCandidates: ['maintainItemName', 'inspectionItemName', 'name', 'itemName'],
resultFieldCandidates: ['maintainResult', 'inspectionResult', 'result'],
methodFieldCandidates: ['inspectionMethod', 'method'],
criteriaFieldCandidates: ['judgmentCriteria', 'criteria'],
imagesFieldCandidates: ['images'],
remarkFieldCandidates: ['remark']
})
)
const repairGroups = computed(() => {
const groupsMap = new Map()
const rows = Array.isArray(repairList.value) ? repairList.value : []
for (const row of rows) {
const groupKey = String(
(row && (row.repairCode || row.repairId || row.subjectName || row.id)) ? (row.repairCode || row.repairId || row.subjectName || row.id) : '-'
)
if (!groupsMap.has(groupKey)) {
groupsMap.set(groupKey, {
key: groupKey,
name: String((row && (row.repairName || row.repairCode)) ? (row.repairName || row.repairCode) : groupKey),
items: []
})
}
const resultMeta = formatResult(row ? (row.repairResult !== undefined ? row.repairResult : row.result) : undefined)
groupsMap.get(groupKey).items.push({
key: String(row && row.id !== undefined && row.id !== null ? row.id : `${groupKey}_${Math.random()}`),
subjectCode: row ? row.subjectCode : undefined,
subjectName: row ? row.subjectName : undefined,
subjectContent: row ? row.subjectContent : undefined,
remark: row ? row.remark : undefined,
finishDateLabel: formatDateOnly(row ? row.finishDate : undefined),
resultLabel: resultMeta.label,
resultType: resultMeta.type,
images: parseImages(row ? (row.malfunctionUrl || row.malfunctionImages) : undefined)
})
}
return Array.from(groupsMap.values())
})
const maintenanceRecords = reactive([
{ title: '定期保养', time: '2024-03-01', type: 'maintenance', typeText: '保养' },
{ title: '模具维修', time: '2024-02-15', type: 'repair', typeText: '维修' },
{ title: '定期保养', time: '2024-01-15', type: 'maintenance', typeText: '保养' },
{ title: '模具更换', time: '2024-01-01', type: 'replace', typeText: '更换' }
]);
function handleTabChange(e) {
const idx = e && typeof e === 'object' ? e.index : e
currentTab.value = Number(idx === 0 ? 0 : idx || 0)
}
function goBack() {
uni.navigateBack();
}
onMounted(() => {
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const options = currentPage.options || {};
if (options.code) {
moldData.code = decodeURIComponent(options.code);
}
onMounted(async () => {
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const options = currentPage && currentPage.options ? currentPage.options : {}
const rawId = options.id !== undefined ? options.id : options.code
const decoded = rawId ? decodeURIComponent(String(rawId)) : ''
moldId.value = decoded ? decoded : undefined
fetchAll()
});
async function fetchAll() {
if (!moldId.value) {
uni.showToast({ title: '缺少模具ID', icon: 'none' })
return
}
loading.value = true
try {
const [detailRes, inspectionRes, maintainRes, repairRes] = await Promise.all([
getMoldDetail(moldId.value),
getMoldInspectionByMoldId(moldId.value),
getMoldMaintenanceByMoldId(moldId.value),
getMoldRepairListByMoldId(moldId.value)
])
detailData.value = detailRes.data
inspectionList.value = normalizeList(inspectionRes)
maintainList.value = normalizeList(maintainRes)
repairList.value = normalizeList(repairRes)
} catch (e) {
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
loading.value = false
}
}
function normalizeList(res) {
const data = res && res.data !== undefined ? res.data : res
if (Array.isArray(data)) return data
if (data && Array.isArray(data.data)) return data.data
if (data && data.data && Array.isArray(data.data.list)) return data.data.list
if (data && data.data && Array.isArray(data.data.rows)) return data.data.rows
if (data && data.data && Array.isArray(data.data.records)) return data.data.records
if (data && Array.isArray(data.list)) return data.list
if (data && Array.isArray(data.rows)) return data.rows
if (data && Array.isArray(data.records)) return data.records
return []
}
function detailValue(v) {
if (v === 0) return '0'
if (v === false) return '否'
if (v === true) return '是'
if (v === null || v === undefined) return '-'
const s = String(v).trim()
return s ? s : '-'
}
function formatEnable(v) {
if (v === true || v === 'true' || v === 1 || v === '1') return '是'
if (v === false || v === 'false' || v === 0 || v === '0') return '否'
return detailValue(v)
}
function formatStatus(v) {
const raw = v === null || v === undefined ? '' : String(v).trim()
const upper = raw.toUpperCase()
if (!raw) return { label: '-', type: 'normal' }
if (raw === '1' || upper === 'OK' || raw.includes('正常')) return { label: raw, type: 'normal' }
if (raw === '2' || upper === 'NG' || raw.includes('停') || raw.includes('禁') || raw.includes('坏') || raw.includes('修'))
return { label: raw, type: 'error' }
return { label: raw, type: 'warning' }
}
function formatResult(v) {
const raw = v === null || v === undefined ? '' : String(v).trim()
const upper = raw.toUpperCase()
if (!raw) return { label: '-', type: 'info' }
if (raw === '0') return { label: '待检测', type: 'info' }
if (raw === '1' || upper === 'OK') return { label: '通过', type: 'success' }
if (raw === '2' || upper === 'NG') return { label: '不通过', type: 'danger' }
return { label: raw, type: 'info' }
}
function formatHistoryTime(value) {
if (!value) return ''
if (Array.isArray(value) && value.length >= 3) {
const [y, m, d, hh, mm, ss] = value
const pad = (n) => String(n).padStart(2, '0')
if (hh !== undefined) return `${y}-${pad(m)}-${pad(d)} ${pad(hh)}:${pad(mm)}:${pad(ss)}`
return `${y}-${pad(m)}-${pad(d)}`
}
const s = String(value).trim()
if (!s) return ''
const num = Number(s)
if (Number.isFinite(num)) {
const ms = s.length === 10 ? num * 1000 : num
const d = new Date(ms)
if (!Number.isNaN(d.getTime())) return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`
}
const d = new Date(s)
if (!Number.isNaN(d.getTime())) return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`
return s
}
function formatDateOnly(value) {
const t = formatHistoryTime(value)
if (!t) return '-'
return String(t).split(' ')[0]
}
function parseImages(value) {
if (!value) return []
if (Array.isArray(value)) return value.map(String).filter(Boolean)
const cleaned = String(value).replace(/[`'"]/g, '').trim()
return cleaned
.split(',')
.map((v) => v.trim())
.filter(Boolean)
}
function pickFirst(obj, keys) {
for (const k of keys) {
if (obj && obj[k] !== undefined && obj[k] !== null && String(obj[k]).trim() !== '') return obj[k]
}
return undefined
}
function buildStepGroups(rows, options) {
const groupsMap = new Map()
const list = Array.isArray(rows) ? rows : []
for (const row of list) {
const time = formatHistoryTime(pickFirst(row, options.timeFieldCandidates) || (row ? row.createTime : undefined))
const operator = detailValue(row ? (row.operator || row.creatorName || row.creator) : undefined)
const managementId = row && row.managementId !== undefined && row.managementId !== null ? row.managementId : ''
const groupKey = `${managementId}__${time}__${operator}`
const name = pickFirst(row, options.nameFieldCandidates) || '-'
const resultMeta = formatResult(pickFirst(row, options.resultFieldCandidates))
const item = {
key: String(row && row.id !== undefined && row.id !== null ? row.id : `${groupKey}_${String(name)}`),
name: detailValue(name),
resultLabel: resultMeta.label,
resultType: resultMeta.type,
method: pickFirst(row, options.methodFieldCandidates),
criteria: pickFirst(row, options.criteriaFieldCandidates),
remark: pickFirst(row, options.remarkFieldCandidates),
images: parseImages(pickFirst(row, options.imagesFieldCandidates)),
taskTimeLabel: formatHistoryTime(row ? (row.taskTime || row.inspectionTime) : undefined),
createTimeLabel: formatHistoryTime(row ? row.createTime : undefined)
}
if (!groupsMap.has(groupKey)) {
groupsMap.set(groupKey, { key: groupKey, time: time || '-', operator, items: [item] })
} else {
groupsMap.get(groupKey).items.push(item)
}
}
return Array.from(groupsMap.values())
}
function previewImages(list, current) {
if (!list || !list.length) return
uni.previewImage({ urls: list, current })
}
</script>
<style lang="scss" scoped>
@ -166,7 +530,7 @@ onMounted(() => {
color: #ffffff;
margin-bottom: 16rpx;
}
.header-code {
display: block;
font-size: 28rpx;
@ -174,37 +538,21 @@ onMounted(() => {
}
}
.status-badge {
padding: 12rpx 24rpx;
border-radius: 24rpx;
font-size: 24rpx;
}
.status-normal {
background: rgba(24, 188, 55, 0.2);
color: #18bc37;
}
.status-warning {
background: rgba(255, 140, 0, 0.2);
color: #ff8c00;
}
.status-error {
background: rgba(255, 77, 79, 0.2);
color: #ff4d4f;
.status-tag {
margin-top: 20rpx;
display: flex;
justify-content: flex-end;
}
.content-section {
padding: 0 30rpx 30rpx;
margin-top: -40rpx;
}
.info-card {
background: #ffffff;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 24rpx;
margin-top: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
}
@ -228,7 +576,7 @@ onMounted(() => {
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f7fa;
&:last-child {
border-bottom: none;
}
@ -242,77 +590,193 @@ onMounted(() => {
.info-value {
font-size: 28rpx;
color: #333333;
&.highlight {
font-weight: 600;
color: #1a3a5c;
}
&.warning {
color: #ff8c00;
font-weight: 500;
}
}
.record-list {
display: flex;
flex-direction: column;
.tabs-box {
margin-bottom: 24rpx;
}
.record-item {
.empty {
padding: 32rpx 0;
text-align: center;
font-size: 28rpx;
color: #999999;
}
.history-group {
background: #f8fafc;
border-radius: 16rpx;
padding: 20rpx;
margin-bottom: 20rpx;
}
.history-group-head {
display: flex;
justify-content: space-between;
align-items: center;
padding: 24rpx 0;
border-bottom: 1rpx solid #f5f7fa;
&:last-child {
border-bottom: none;
}
margin-bottom: 16rpx;
}
.record-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background: #1a3a5c;
margin-right: 20rpx;
.history-group-time {
font-size: 24rpx;
color: #1a3a5c;
font-weight: 600;
}
.record-content {
flex: 1;
.record-title {
display: block;
font-size: 28rpx;
color: #333333;
margin-bottom: 8rpx;
}
.record-time {
display: block;
font-size: 24rpx;
color: #999999;
}
.history-group-operator {
font-size: 24rpx;
color: #666666;
}
.history-item {
background: #ffffff;
border-radius: 14rpx;
padding: 18rpx;
margin-bottom: 16rpx;
}
.history-item:last-child {
margin-bottom: 0;
}
.history-item-head {
display: flex;
align-items: center;
margin-bottom: 14rpx;
}
.record-type {
padding: 8rpx 16rpx;
border-radius: 8rpx;
.history-item-name {
font-size: 28rpx;
color: #333333;
font-weight: 600;
}
.result-badge {
padding: 6rpx 14rpx;
border-radius: 999rpx;
font-size: 22rpx;
margin-right: 14rpx;
}
.type-maintenance {
background: rgba(24, 188, 55, 0.1);
.result-success {
background: rgba(24, 188, 55, 0.12);
color: #18bc37;
}
.type-repair {
background: rgba(255, 140, 0, 0.1);
color: #ff8c00;
.result-danger {
background: rgba(255, 77, 79, 0.12);
color: #ff4d4f;
}
.result-info {
background: rgba(153, 153, 153, 0.12);
color: #666666;
}
.history-item-body {
display: flex;
flex-direction: column;
}
.history-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 10rpx 0;
}
.history-label {
font-size: 24rpx;
color: #999999;
width: 160rpx;
flex-shrink: 0;
}
.type-replace {
background: rgba(74, 144, 194, 0.1);
color: #4a90c2;
.history-value {
font-size: 24rpx;
color: #333333;
flex: 1;
text-align: right;
}
.history-images {
margin-top: 12rpx;
display: flex;
flex-wrap: wrap;
gap: 12rpx;
}
.history-image {
width: 160rpx;
height: 160rpx;
border-radius: 12rpx;
background: #f0f2f5;
}
.repair-group {
background: #f8fafc;
border-radius: 16rpx;
padding: 20rpx;
margin-bottom: 20rpx;
}
.repair-group-head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.repair-group-name {
font-size: 28rpx;
color: #1a3a5c;
font-weight: 600;
}
.repair-group-meta {
font-size: 24rpx;
color: #666666;
}
.repair-item {
background: #ffffff;
border-radius: 14rpx;
padding: 18rpx;
margin-bottom: 16rpx;
}
.repair-item:last-child {
margin-bottom: 0;
}
.repair-item-head {
display: flex;
align-items: center;
margin-bottom: 14rpx;
}
.repair-tag {
padding: 6rpx 14rpx;
border-radius: 999rpx;
font-size: 22rpx;
background: rgba(74, 144, 194, 0.12);
color: #2d5a87;
margin-right: 14rpx;
}
.repair-title {
font-size: 28rpx;
color: #333333;
font-weight: 600;
}
</style>

@ -120,7 +120,7 @@ function confirmInput() {
function navigateToDetail(code) {
uni.navigateTo({
url: `/pages_function/pages/mold/detail?code=${encodeURIComponent(code)}`
url: `/pages_function/pages/mold/detail?id=${encodeURIComponent(code)}`
});
}
</script>
@ -176,7 +176,6 @@ function navigateToDetail(code) {
.content-section {
padding: 40rpx 30rpx;
margin-top: -40rpx;
}
.scan-section {

@ -1,3 +1,5 @@
let loadingCount = 0
export default {
/**
*
@ -86,14 +88,22 @@ export default {
* @param content
*/
loading(content: string): void {
if (!content) {
content = '加载中'
}
loadingCount += 1
uni.showLoading({
title: content
title: content,
mask: true
})
},
/**
*
*/
closeLoading(): void {
uni.hideLoading()
loadingCount = Math.max(loadingCount - 1, 0)
if (loadingCount === 0) {
uni.hideLoading()
}
}
}

@ -2,11 +2,12 @@ import { defineStore } from "pinia";
const useDictStore = defineStore("dict", {
state: () => ({
dict: new Array(),
loadedAll: false,
}),
actions: {
// 获取字典
getDict(_key: string) {
if (_key == null && _key == "") {
if (_key == null || _key == "") {
return null;
}
try {
@ -22,12 +23,16 @@ const useDictStore = defineStore("dict", {
// 设置字典
setDict(_key: string, value: any) {
if (_key !== null && _key !== "") {
this.removeDict(_key);
this.dict.push({
key: _key,
value: value,
});
}
},
setLoadedAll(loaded: boolean) {
this.loadedAll = loaded;
},
// 删除字典
removeDict(_key: string) {
var bln = false;

@ -2,6 +2,7 @@ import { login, logout, getInfo } from "@/api/login";
import { getToken, setToken, removeToken } from "@/utils/auth";
import defAva from "@/static/images/profile.jpg";
import { defineStore } from "pinia";
import { initAllDict } from "@/utils/dict";
export interface LoginForm {
username: string;
@ -65,6 +66,7 @@ const useUserStore = defineStore("user", {
this.name = user.nickname;
this.userId = user.id;
this.avatar = avatar;
initAllDict().catch(() => {});
resolve(res);
})
.catch((error) => {

@ -11,6 +11,10 @@ interface BaseRequestConfig {
params?: any,
/** 超时事件 */
timeout?: number | undefined,
/** 是否显示全局loading弹框默认显示 */
showLoading?: boolean,
/** loading文案 */
loadingText?: string,
}
export interface RequestConfig extends BaseRequestConfig {
/** 请求方式 */

@ -1,7 +1,72 @@
import useDictStore from "@/store/modules/dict";
import { getDicts } from "@/api/system/dict/data";
import { getDicts, getSimpleDictList } from "@/api/system/dict/data";
import { Ref, ref, toRefs } from "vue";
type DictItem = {
label: string;
value: string | number;
elTagType?: string;
elTagClass?: string;
};
function normalizeDictItem(p: any): DictItem {
const label = p?.dictLabel ?? p?.label ?? "";
const value = p?.dictValue ?? p?.value ?? "";
return {
label: String(label),
value: typeof value === "number" ? value : String(value),
elTagType: p?.colorType ?? p?.listClass ?? p?.elTagType,
elTagClass: p?.cssClass ?? p?.elTagClass,
};
}
function groupByDictType(raw: any): Record<string, DictItem[]> {
const data = raw?.data ?? raw;
const groups: Record<string, DictItem[]> = {};
if (Array.isArray(data)) {
data.forEach((row) => {
const dictType = row?.dictType ?? row?.type ?? row?.dictCode;
if (!dictType) return;
const key = String(dictType);
if (!groups[key]) groups[key] = [];
groups[key].push(normalizeDictItem(row));
});
return groups;
}
if (data && typeof data === "object") {
Object.keys(data).forEach((k) => {
const list = data[k];
if (!Array.isArray(list)) return;
groups[k] = list.map((row: any) => normalizeDictItem(row));
});
}
return groups;
}
export async function initAllDict(force: boolean = false) {
const dictStore = useDictStore();
if (!force && dictStore.loadedAll) return;
const resp = await getSimpleDictList();
const groups = groupByDictType(resp);
Object.keys(groups).forEach((dictType) => {
dictStore.setDict(dictType, groups[dictType]);
});
dictStore.setLoadedAll(true);
}
export function getDictLabel(dictType: string, value: any, defaultLabel: string = "-") {
const dictStore = useDictStore();
const dicts: DictItem[] = (dictStore.getDict(dictType) as any) || [];
const v = value === null || value === undefined ? "" : String(value);
for (let i = 0; i < dicts.length; i++) {
const item = dicts[i];
if (String(item.value) === v) return item.label;
}
return defaultLabel;
}
/**
*
*/

@ -3,6 +3,7 @@ import { getToken, removeToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { toast, showConfirm, tansParams } from '@/utils/common'
import { RequestConfig, ResponseData } from '@/types/request'
import modal from '@/plugins/modal'
let timeout = 10000
const baseUrl = config.baseUrl
@ -22,6 +23,10 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
config.url = url
}
return new Promise((resolve, reject) => {
const shouldShowLoading = config.showLoading !== false
if (shouldShowLoading) {
modal.loading(config.loadingText || '加载中')
}
uni.request({
method: config.method || 'GET',
timeout: config.timeout || timeout,
@ -52,12 +57,15 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
reject('无效的会话,或者会话已过期,请重新登录。')
removeToken()
uni.reLaunch({ url: '/pages/login' })
return
} else if (code === 500) {
toast(msg)
reject('500')
return
} else if (code !== 200) {
toast(msg)
reject(code)
return
}
resolve(data)
})
@ -73,6 +81,11 @@ const request = <T>(config: RequestConfig): Promise<ResponseData<T>> => {
toast(message)
reject(error)
})
.finally(() => {
if (shouldShowLoading) {
modal.closeLoading()
}
})
})
}

@ -3,6 +3,7 @@ import { getToken, removeToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { toast, showConfirm, tansParams } from '@/utils/common'
import { ResponseData, RequestUploadConfig } from '@/types/request'
import modal from '@/plugins/modal'
let timeout = 10000
const baseUrl = config.baseUrl
@ -21,6 +22,10 @@ const upload = <T>(config: RequestUploadConfig): Promise<ResponseData<T>> => {
config.url = url
}
return new Promise((resolve, reject) => {
const shouldShowLoading = config.showLoading !== false
if (shouldShowLoading) {
modal.loading(config.loadingText || '加载中')
}
uni.uploadFile({
timeout: config.timeout || timeout,
url: baseUrl + config.url,
@ -43,12 +48,15 @@ const upload = <T>(config: RequestUploadConfig): Promise<ResponseData<T>> => {
}
})
reject('无效的会话,或者会话已过期,请重新登录。')
return
} else if (code === 500) {
toast(msg)
reject('500')
return
} else if (code !== 200) {
toast(msg)
reject(code)
return
}
},
fail: (error: any) => {
@ -62,6 +70,11 @@ const upload = <T>(config: RequestUploadConfig): Promise<ResponseData<T>> => {
}
toast(message)
reject(error)
},
complete: () => {
if (shouldShowLoading) {
modal.closeLoading()
}
}
})
})

@ -1,5 +1,5 @@
{
"exclude": ["node_modules"],
"exclude": ["node_modules", "src/pages_function/pages/mold/index copy.vue"],
"compilerOptions": {
"noImplicitAny": true,
"importHelpers": true,

Loading…
Cancel
Save