feat:首页模块对接接口

master
黄伟杰 2 months ago
parent b943caa4f9
commit 93da020626

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

@ -1,7 +1,7 @@
// 应用全局配置 // 应用全局配置
const config = { const config = {
// baseUrl: 'http://47.106.185.127:48080',127.0.0.1 // baseUrl: 'http://47.106.185.127:48080',127.0.0.1
baseUrl: 'http://localhost:48081', baseUrl: 'https://besure.ngsk.tech:7001',
// 应用信息 // 应用信息
appInfo: { appInfo: {
// 应用名称 // 应用名称

@ -12,9 +12,12 @@
<view class="deco-dot"></view> <view class="deco-dot"></view>
</view> </view>
</view> </view>
<view class="bell-icon" @click="showTodoList"> <view class="bell-wrapper" @click="showTodoList">
<text class="iconfont icon-bell"></text> <text class="bell-icon">
<view v-if="todoCount > 0" class="bell-badge">{{ todoCount }}</view> <el-badge :value="todoCount" :hidden="todoCount === 0" class="item">
<image src="/static/logo/bell.png" mode="aspectFit" style="width: 48rpx; height: 48rpx;" />
</el-badge>
</text>
</view> </view>
</view> </view>
@ -22,12 +25,7 @@
<view class="nav-section"> <view class="nav-section">
<view class="section-title">功能导航</view> <view class="section-title">功能导航</view>
<view class="nav-grid"> <view class="nav-grid">
<view <view v-for="(item, index) in navList" :key="index" class="nav-item" @click="handleNavClick(item)">
v-for="(item, index) in navList"
:key="index"
class="nav-item"
@click="handleNavClick(item)"
>
<view class="nav-icon" :style="{ backgroundColor: item.bgColor }"> <view class="nav-icon" :style="{ backgroundColor: item.bgColor }">
<text class="nav-icon-text">{{ item.icon }}</text> <text class="nav-icon-text">{{ item.icon }}</text>
</view> </view>
@ -39,12 +37,7 @@
<view class="stats-section"> <view class="stats-section">
<view class="section-title">生产整体概况</view> <view class="section-title">生产整体概况</view>
<view class="stats-grid"> <view class="stats-grid">
<view <view v-for="(stat, index) in statsData" :key="index" class="stat-card" :class="'stat-' + stat.type">
v-for="(stat, index) in statsData"
:key="index"
class="stat-card"
:class="'stat-' + stat.type"
>
<text class="stat-value">{{ stat.value }}</text> <text class="stat-value">{{ stat.value }}</text>
<text class="stat-label">{{ stat.label }}</text> <text class="stat-label">{{ stat.label }}</text>
</view> </view>
@ -57,12 +50,7 @@
<text class="section-more" @click="viewMorePlans"> </text> <text class="section-more" @click="viewMorePlans"> </text>
</view> </view>
<view class="plan-list"> <view class="plan-list">
<view <view v-for="(plan, index) in planList" :key="index" class="plan-card" @click="handlePlanClick(plan)">
v-for="(plan, index) in planList"
:key="index"
class="plan-card"
@click="handlePlanClick(plan)"
>
<view class="plan-header"> <view class="plan-header">
<text class="plan-code">{{ plan.code }}</text> <text class="plan-code">{{ plan.code }}</text>
<view class="plan-status" :class="'status-' + plan.statusType"> <view class="plan-status" :class="'status-' + plan.statusType">
@ -76,11 +64,19 @@
</view> </view>
<view class="plan-row"> <view class="plan-row">
<text class="plan-label">生产线</text> <text class="plan-label">生产线</text>
<text class="plan-value">{{ plan.lineName }}</text> <text class="plan-value">{{ plan.feedingPipelineName }}</text>
</view> </view>
<view class="plan-row"> <view class="plan-row">
<text class="plan-label">计划数量</text> <text class="plan-label">计划数量</text>
<text class="plan-value plan-num">{{ plan.quantity }}</text> <text class="plan-value plan-num">{{ plan.planNumber }}</text>
</view>
<view class="plan-row">
<text class="plan-label">计划开始</text>
<text class="plan-value">{{ plan.planStartTimeText }}</text>
</view>
<view class="plan-row">
<text class="plan-label">计划结束</text>
<text class="plan-value">{{ plan.planEndTimeText }}</text>
</view> </view>
</view> </view>
</view> </view>
@ -103,18 +99,14 @@
<text class="empty-text">暂无待办任务</text> <text class="empty-text">暂无待办任务</text>
</view> </view>
<view v-else> <view v-else>
<view <view v-for="(item, index) in todoList" :key="index" class="todo-item">
v-for="(item, index) in todoList"
:key="index"
class="todo-item"
>
<view class="todo-dot"></view> <view class="todo-dot"></view>
<view class="todo-content"> <view class="todo-content">
<text class="todo-name">{{ item.name }}</text> <view class="todo-title" style="text-align: left;margin-right: 0;">{{ item.name }}</view>
<text class="todo-time">{{ item.time }}</text> <view class="todo-sub">任务编号{{ item.code }}</view>
</view> <view class="todo-sub">任务类型{{ item.type }}</view>
<view class="todo-priority" :class="'priority-' + item.priority"> <view class="todo-sub">目标{{ item.deviceName }}</view>
<text>{{ item.priorityText }}</text> <view class="todo-sub">创建时间{{ formatDate(item.createTime) }}</view>
</view> </view>
</view> </view>
</view> </view>
@ -125,10 +117,11 @@
</template> </template>
<script setup> <script setup>
import { ref, reactive } from 'vue'; import { onMounted, ref, reactive } from 'vue';
import request from '@/utils/request'
const todoPopup = ref(null); const todoPopup = ref(null);
const todoCount = ref(5); const todoCount = ref(0);
const navList = reactive([ const navList = reactive([
{ name: '模具', icon: '🔧', bgColor: '#1a3a5c', path: '/pages_function/mold' }, { name: '模具', icon: '🔧', bgColor: '#1a3a5c', path: '/pages_function/mold' },
@ -139,26 +132,15 @@ const navList = reactive([
]); ]);
const statsData = reactive([ const statsData = reactive([
{ label: '总数', value: 128, type: 'total' }, { label: '总数', type: 'total' },
{ label: '未开工', value: 24, type: 'pending' }, { label: '未开工', type: 'pending' },
{ label: '生产中', value: 86, type: 'running' }, { label: '生产中', type: 'running' },
{ label: '完工', value: 18, type: 'finished' } { label: '完工', type: 'finished' }
]); ]);
const planList = reactive([ const planList = reactive([]);
{ code: 'PO-20240312-001', status: '生产中', statusType: 'running', productName: '汽车零部件A型', lineName: '一号生产线', quantity: 1000 },
{ code: 'PO-20240312-002', status: '未开工', statusType: 'pending', productName: '精密齿轮组件', lineName: '二号生产线', quantity: 500 },
{ code: 'PO-20240311-003', status: '完工', statusType: 'finished', productName: '电机外壳套件', lineName: '三号生产线', quantity: 2000 },
{ code: 'PO-20240311-004', status: '生产中', statusType: 'running', productName: '传动轴总成', lineName: '一号生产线', quantity: 800 }
]);
const todoList = reactive([ const todoList = reactive([]);
{ name: '生产计划审批', time: '2024-03-12 10:30', priority: 'high', priorityText: '紧急' },
{ name: '设备维护确认', time: '2024-03-12 11:00', priority: 'medium', priorityText: '一般' },
{ name: '物料领用审核', time: '2024-03-12 14:00', priority: 'medium', priorityText: '一般' },
{ name: '质量异常处理', time: '2024-03-12 15:30', priority: 'high', priorityText: '紧急' },
{ name: '完工报告确认', time: '2024-03-12 16:00', priority: 'low', priorityText: '普通' }
]);
function showTodoList() { function showTodoList() {
todoPopup.value.open(); todoPopup.value.open();
@ -203,6 +185,91 @@ function viewMorePlans() {
function onScroll(e) { function onScroll(e) {
} }
function formatDate(ms) {
if (!ms) return '-'
const date = new Date(ms)
if (Number.isNaN(date.getTime())) return '-'
const pad2 = (n) => String(n).padStart(2, '0')
const y = date.getFullYear()
const m = pad2(date.getMonth() + 1)
const d = pad2(date.getDate())
return `${y}-${m}-${d}`
}
const getPlanStatusLabel = (value) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v == '1') return '已排产'
if (v == '6') return '试产'
if (v == '2') return '量产'
if (v == '3') return '暂停'
if (v == '4') return '待入库'
return '-'
}
function mapPlanStatus(status) {
const v = status === '' || status === null || status === undefined ? undefined : String(status)
if (v == '1') return { status: getPlanStatusLabel(v), statusType: 'pending' }
if (v == '6') return { status: getPlanStatusLabel(v), statusType: 'running' }
if (v == '2') return { status: getPlanStatusLabel(v), statusType: 'running' }
if (v == '3') return { status: getPlanStatusLabel(v), statusType: 'pending' }
if (v == '4') return { status: getPlanStatusLabel(v), statusType: 'finished' }
return { status: getPlanStatusLabel(v), statusType: 'pending' }
}
async function loadProductionStats() {
const res = await request({ url: '/admin-api/mes/dashboard/getProduction', method: 'get' })
const taskItems = (res?.data?.taskItems || []).map((i) => ({
key: String(i.key),
value: Number(i.value ?? 0)
}))
const byKey = taskItems.reduce((acc, cur) => {
acc[cur.key] = cur.value
return acc
}, {})
const keyOrder = ['1', '2', '3', '4']
statsData.forEach((stat, index) => {
const k = keyOrder[index]
stat.value = byKey[k] ?? 0
})
}
async function loadPlanList() {
const res = await request({ url: '/admin-api/mes/dashboard/getPlan', method: 'get' })
const raw = Array.isArray(res?.data) ? res.data : (res?.data ? [res.data] : [])
const mapped = raw.map((p) => {
const statusInfo = mapPlanStatus(p?.status)
return {
id: p?.id,
code: p?.code ?? '-',
status: statusInfo.status,
statusType: statusInfo.statusType,
productName: p?.productName ?? '-',
feedingPipelineName: p?.feedingPipelineName ?? '-',
planNumber: p?.planNumber ?? 0,
planStartTimeText: formatDate(p?.planStartTime),
planEndTimeText: formatDate(p?.planEndTime),
}
})
if (mapped.length) {
planList.splice(0, planList.length, ...mapped)
}
}
async function loadTodoList() {
const res = await request({ url: '/admin-api/mes/dashboard/getTodoList', method: 'get' })
const data = res?.data || []
todoList.splice(0, todoList.length, ...data)
todoCount.value = data.length
}
async function loadDashboard() {
await Promise.allSettled([loadProductionStats(), loadPlanList(), loadTodoList()])
}
onMounted(() => {
loadDashboard()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -297,7 +364,7 @@ function onScroll(e) {
} }
} }
.bell-icon { .bell-wrapper {
position: absolute; position: absolute;
top: 30rpx; top: 30rpx;
right: 30rpx; right: 30rpx;
@ -307,28 +374,14 @@ function onScroll(e) {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
z-index: 100; z-index: 100;
}
.iconfont { .bell-icon {
font-size: 48rpx; display: flex;
color: #ff4d4f; align-items: center;
} justify-content: center;
width: 100%;
.bell-badge { height: 100%;
position: absolute;
top: -8rpx;
right: -8rpx;
min-width: 32rpx;
height: 32rpx;
background: #ff4d4f;
border-radius: 16rpx;
font-size: 20rpx;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
padding: 0 8rpx;
border: 2rpx solid #ffffff;
}
} }
@ -650,17 +703,20 @@ function onScroll(e) {
.todo-content { .todo-content {
flex: 1; flex: 1;
.todo-name { .todo-title {
display: block; display: block;
font-size: 28rpx; font-size: 28rpx;
color: #333333; color: #333333;
margin-bottom: 8rpx; font-weight: bold;
margin-bottom: 12rpx;
} }
.todo-time { .todo-sub {
display: block; display: block;
font-size: 24rpx; font-size: 24rpx;
color: #999999; color: #666666;
margin-bottom: 6rpx;
line-height: 1.4;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Loading…
Cancel
Save