feat:首页模块对接接口

master
黄伟杰 1 month 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 = {
// baseUrl: 'http://47.106.185.127:48080',127.0.0.1
baseUrl: 'http://localhost:48081',
baseUrl: 'https://besure.ngsk.tech:7001',
// 应用信息
appInfo: {
// 应用名称

@ -12,9 +12,12 @@
<view class="deco-dot"></view>
</view>
</view>
<view class="bell-icon" @click="showTodoList">
<text class="iconfont icon-bell"></text>
<view v-if="todoCount > 0" class="bell-badge">{{ todoCount }}</view>
<view class="bell-wrapper" @click="showTodoList">
<text class="bell-icon">
<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>
@ -22,12 +25,7 @@
<view class="nav-section">
<view class="section-title">功能导航</view>
<view class="nav-grid">
<view
v-for="(item, index) in navList"
:key="index"
class="nav-item"
@click="handleNavClick(item)"
>
<view v-for="(item, index) in navList" :key="index" class="nav-item" @click="handleNavClick(item)">
<view class="nav-icon" :style="{ backgroundColor: item.bgColor }">
<text class="nav-icon-text">{{ item.icon }}</text>
</view>
@ -39,12 +37,7 @@
<view class="stats-section">
<view class="section-title">生产整体概况</view>
<view class="stats-grid">
<view
v-for="(stat, index) in statsData"
:key="index"
class="stat-card"
:class="'stat-' + stat.type"
>
<view 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-label">{{ stat.label }}</text>
</view>
@ -57,12 +50,7 @@
<text class="section-more" @click="viewMorePlans"> </text>
</view>
<view class="plan-list">
<view
v-for="(plan, index) in planList"
:key="index"
class="plan-card"
@click="handlePlanClick(plan)"
>
<view v-for="(plan, index) in planList" :key="index" class="plan-card" @click="handlePlanClick(plan)">
<view class="plan-header">
<text class="plan-code">{{ plan.code }}</text>
<view class="plan-status" :class="'status-' + plan.statusType">
@ -76,11 +64,19 @@
</view>
<view class="plan-row">
<text class="plan-label">生产线</text>
<text class="plan-value">{{ plan.lineName }}</text>
<text class="plan-value">{{ plan.feedingPipelineName }}</text>
</view>
<view class="plan-row">
<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>
@ -103,18 +99,14 @@
<text class="empty-text">暂无待办任务</text>
</view>
<view v-else>
<view
v-for="(item, index) in todoList"
:key="index"
class="todo-item"
>
<view v-for="(item, index) in todoList" :key="index" class="todo-item">
<view class="todo-dot"></view>
<view class="todo-content">
<text class="todo-name">{{ item.name }}</text>
<text class="todo-time">{{ item.time }}</text>
</view>
<view class="todo-priority" :class="'priority-' + item.priority">
<text>{{ item.priorityText }}</text>
<view class="todo-title" style="text-align: left;margin-right: 0;">{{ item.name }}</view>
<view class="todo-sub">任务编号{{ item.code }}</view>
<view class="todo-sub">任务类型{{ item.type }}</view>
<view class="todo-sub">目标{{ item.deviceName }}</view>
<view class="todo-sub">创建时间{{ formatDate(item.createTime) }}</view>
</view>
</view>
</view>
@ -125,10 +117,11 @@
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onMounted, ref, reactive } from 'vue';
import request from '@/utils/request'
const todoPopup = ref(null);
const todoCount = ref(5);
const todoCount = ref(0);
const navList = reactive([
{ name: '模具', icon: '🔧', bgColor: '#1a3a5c', path: '/pages_function/mold' },
@ -139,26 +132,15 @@ const navList = reactive([
]);
const statsData = reactive([
{ label: '总数', value: 128, type: 'total' },
{ label: '未开工', value: 24, type: 'pending' },
{ label: '生产中', value: 86, type: 'running' },
{ label: '完工', value: 18, type: 'finished' }
{ label: '总数', type: 'total' },
{ label: '未开工', type: 'pending' },
{ label: '生产中', type: 'running' },
{ label: '完工', type: 'finished' }
]);
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 planList = 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: '普通' }
]);
const todoList = reactive([]);
function showTodoList() {
todoPopup.value.open();
@ -175,7 +157,7 @@ function handleNavClick(item) {
'备件': '/pages_function/pages/spare/index',
'关键件': '/pages_function/pages/keypart/index'
};
const url = navMap[item.name];
if (url) {
uni.navigateTo({ url });
@ -203,6 +185,91 @@ function viewMorePlans() {
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>
<style lang="scss" scoped>
@ -229,7 +296,7 @@ function onScroll(e) {
background: linear-gradient(135deg, #1a3a5c 0%, #2d5a87 50%, #3d7ab5 100%);
position: relative;
overflow: visible;
&::before {
content: '';
position: absolute;
@ -240,7 +307,7 @@ function onScroll(e) {
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
}
&::after {
content: '';
position: absolute;
@ -257,14 +324,14 @@ function onScroll(e) {
position: relative;
z-index: 2;
padding: 60rpx 40rpx;
.banner-title {
display: block;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 16rpx;
}
.banner-subtitle {
display: block;
font-size: 40rpx;
@ -280,14 +347,14 @@ function onScroll(e) {
left: 40rpx;
display: flex;
align-items: center;
.deco-line {
width: 60rpx;
height: 4rpx;
background: #ff8c00;
border-radius: 2rpx;
}
.deco-dot {
width: 12rpx;
height: 12rpx;
@ -297,7 +364,7 @@ function onScroll(e) {
}
}
.bell-icon {
.bell-wrapper {
position: absolute;
top: 30rpx;
right: 30rpx;
@ -307,28 +374,14 @@ function onScroll(e) {
align-items: center;
justify-content: center;
z-index: 100;
.iconfont {
font-size: 48rpx;
color: #ff4d4f;
}
.bell-badge {
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;
}
}
.bell-icon {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
@ -351,7 +404,7 @@ function onScroll(e) {
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.section-more {
font-size: 26rpx;
color: #666666;
@ -375,7 +428,7 @@ function onScroll(e) {
display: flex;
flex-direction: column;
align-items: center;
&:active {
opacity: 0.7;
}
@ -389,7 +442,7 @@ function onScroll(e) {
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
.nav-icon-text {
font-size: 44rpx;
}
@ -417,15 +470,15 @@ function onScroll(e) {
margin: 0 8rpx;
text-align: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
&:active {
transform: scale(0.98);
}
@ -446,7 +499,7 @@ function onScroll(e) {
.stat-total {
border-left: 6rpx solid #1a3a5c;
.stat-value {
color: #1a3a5c;
}
@ -454,7 +507,7 @@ function onScroll(e) {
.stat-pending {
border-left: 6rpx solid #ff8c00;
.stat-value {
color: #ff8c00;
}
@ -462,7 +515,7 @@ function onScroll(e) {
.stat-running {
border-left: 6rpx solid #18bc37;
.stat-value {
color: #18bc37;
}
@ -470,7 +523,7 @@ function onScroll(e) {
.stat-finished {
border-left: 6rpx solid #4a90c2;
.stat-value {
color: #4a90c2;
}
@ -493,11 +546,11 @@ function onScroll(e) {
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
&:active {
background: #e8f4ff;
}
@ -547,7 +600,7 @@ function onScroll(e) {
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
&:last-child {
margin-bottom: 0;
}
@ -584,17 +637,17 @@ function onScroll(e) {
.todo-back {
display: flex;
align-items: center;
&:active {
opacity: 0.7;
}
.back-icon {
font-size: 48rpx;
color: #ffffff;
margin-right: 8rpx;
}
.back-text {
font-size: 28rpx;
color: #ffffff;
@ -620,7 +673,7 @@ function onScroll(e) {
align-items: center;
justify-content: center;
height: 400rpx;
.empty-text {
font-size: 28rpx;
color: #999999;
@ -633,7 +686,7 @@ function onScroll(e) {
background: #ffffff;
padding: 28rpx 30rpx;
margin-bottom: 2rpx;
&:active {
background: #f5f7fa;
}
@ -649,18 +702,21 @@ function onScroll(e) {
.todo-content {
flex: 1;
.todo-name {
.todo-title {
display: block;
font-size: 28rpx;
color: #333333;
margin-bottom: 8rpx;
font-weight: bold;
margin-bottom: 12rpx;
}
.todo-time {
.todo-sub {
display: block;
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