feat: 新增油漆件叫料与收料功能及相关页面

refactor: 优化首页菜单图标显示方式

fix: 修复SignalR连接初始化问题

style: 更新manifest.json版本号至2.0.0

chore: 新增多个SVG图标资源

perf: 为登录接口添加超时处理

docs: 更新API接口文档

test: 添加油漆件叫料相关测试用例

build: 更新依赖版本
This commit is contained in:
赵正易 2025-08-06 10:25:23 +08:00
parent 5239e90611
commit a8dbe84e25
17 changed files with 923 additions and 80 deletions

View File

@ -2,60 +2,61 @@ import request from '@/utils/request'
// 登录方法
export function login(username, password, code, uuid, clientId) {
const data = {
username,
password,
code,
uuid,
clientId
}
return request({
'url': '/login',
headers: {
isToken: false,
userName: username
},
'method': 'post',
'data': data
})
const data = {
username,
password,
code,
uuid,
clientId
}
return request({
'url': '/login',
headers: {
isToken: false,
userName: username
},
timeout: 3000,
'method': 'post',
'data': data
})
}
// 注册方法
export function register(data) {
return request({
url: '/register',
headers: {
isToken: false
},
method: 'post',
data: data
})
return request({
url: '/register',
headers: {
isToken: false
},
method: 'post',
data: data
})
}
// 获取用户详细信息
export function getInfo() {
return request({
'url': '/getInfo',
'method': 'get'
})
return request({
'url': '/getInfo',
'method': 'get'
})
}
// 退出方法
export function logout() {
return request({
'url': '/logout',
'method': 'post'
})
return request({
'url': '/logout',
'method': 'post'
})
}
// 获取验证码
export function getCodeImg() {
return request({
'url': '/captchaImage',
headers: {
isToken: false
},
method: 'get',
timeout: 20000
})
}
return request({
'url': '/captchaImage',
headers: {
isToken: false
},
method: 'get',
timeout: 20000
})
}

98
api/mmcall/index.js Normal file
View File

@ -0,0 +1,98 @@
import request from '@/utils/request'
// 查询叫料需求表列表
export function getMmCallList(params) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/list',
method: 'get',
params
})
}
// 查询线别MRP表
export function queryCallMaterialMRP(params) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/QueryCallMaterialMRP',
method: 'get',
params
})
}
// 获取线清单 groupCode groupName
export function getLineOptions(params) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/GetLineOptions',
method: 'get',
params
})
}
// 查询叫料需求表详情
export function getMmCallInfo(Id) {
return request({
url: `/mes/materialManagement/paintedparts_call/mmcall/${Id}`,
method: 'get'
})
}
// 添加叫料需求表
export function addMmCall(data) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall',
method: 'post',
data
})
}
// 更新叫料需求表
export function updateMmCall(data) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall',
method: 'put',
data
})
}
// 删除叫料需求表
export function deleteMmCall(ids) {
return request({
url: `/mes/materialManagement/paintedparts_call/mmcall/${ids}`,
method: 'delete'
})
}
// 生成产线油漆件MRP
export function generateLineMmCallMRP(data) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/GenerateLineMmCallMRP',
method: 'post',
data
})
}
// 涂装油漆件产线叫料
export function doLineCallMaterial(data) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/DoLineCallMaterial',
method: 'post',
data
})
}
// 涂装油漆件产线领料
export function doLineReceiveMaterial(data) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/DoLineReceiveMaterial',
method: 'post',
data
})
}
// 涂装油漆件产线退料
export function doLineReturnBackMaterial(data) {
return request({
url: '/mes/materialManagement/paintedparts_call/mmcall/DoLineReturnBackMaterial',
method: 'post',
data
})
}

View File

@ -2,8 +2,8 @@
"name": "DOAN总装车间PDA",
"appid": "__UNI__EFA389B",
"description": "DOAN总装车间PDA",
"versionName": "1.5.0",
"versionCode": 150,
"versionName": "2.0.0",
"versionCode": 200,
"transformPx": false,
"app-plus": {
"networkTimeout": {

View File

@ -196,6 +196,20 @@
{
"navigationBarTitleText" : "U03,U05线报工"
}
},
{
"path" : "pages/produceManagement/paintMaterial/paint_call",
"style" :
{
"navigationBarTitleText" : "产线油漆件叫料"
}
},
{
"path" : "pages/produceManagement/paintMaterial/paint_receive",
"style" :
{
"navigationBarTitleText" : "产线油漆件收料"
}
}
],
"tabBar": {

View File

@ -17,7 +17,7 @@
<uni-grid :column="4" :showBorder="false" @change="changeProduceGrid">
<uni-grid-item v-for="(item, index) in produceOptions" :key="index" :index="index">
<view class="grid-item-box">
<uni-icons :type="item.icon" size="30"></uni-icons>
<image :src="item.iconPath" mode="aspectFit" class="menu-icon"></image>
<text class="text">{{ item.name }}</text>
</view>
</uni-grid-item>
@ -28,7 +28,7 @@
<uni-grid :column="4" :showBorder="false" @change="changeMaterialGrid">
<uni-grid-item v-for="(item, index) in materialOptions" :key="index" :index="index">
<view class="grid-item-box">
<uni-icons :type="item.icon" size="30"></uni-icons>
<image :src="item.iconPath" mode="aspectFit" class="menu-icon"></image>
<text class="text">{{ item.name }}</text>
</view>
</uni-grid-item>
@ -46,7 +46,7 @@ export default {
},
data() {
return {
socketRef:null,
socketRef: null,
current: 0,
swiperDotIndex: 0,
bannerList: [
@ -64,30 +64,40 @@ export default {
produceOptions: [
{
name: '产线报工(通用)',
icon: 'folder-add-filled',
iconPath: '/static/images/index_menu_icon/work_report_common.svg',
url: '/pages/produceManagement/workorder/workorder'
},
{
name: '产线报工\n(U16线U17线)',
icon: 'folder-add-filled',
iconPath: '/static/images/index_menu_icon/work_report_u16u17.svg',
url: '/pages/produceManagement/workorder/workorder02'
},
{
name: '产线报工\n(U03线U05线)',
icon: 'folder-add-filled',
iconPath: '/static/images/index_menu_icon/work_report_u03u05.svg',
url: '/pages/produceManagement/workorder/workorder03'
},
{
name: '安灯报警',
icon: 'notification-filled',
iconPath: '/static/images/index_menu_icon/andon_alarm.svg',
url: '/pages/produceManagement/andon/alarm'
},
{
name: '产线油漆件叫料',
iconPath: '/static/images/index_menu_icon/paint_call.svg',
url: '/pages/produceManagement/paintMaterial/paint_call'
},
{
name: '产线油漆件收料',
iconPath: '/static/images/index_menu_icon/paint_receive.svg',
url: '/pages/produceManagement/paintMaterial/paint_receive'
}
],
//
materialOptions: [
{
name: '产线备料',
icon: 'upload-filled',
iconPath: '/static/images/index_menu_icon/material_preparation.svg',
url: '/pages/materialManagement/preparationByPlan/index'
}
// {
@ -128,8 +138,28 @@ export default {
// renderjs
handleGetStorage() {
const value = getBaseUrl();
console.log('handleGetStorage', this.$refs.socketRef);
this.$refs.socketRef.receiveStorageValue(value);
const maxRetries = 5;
const initialDelay = 300;
let retries = 0;
const attemptCall = () => {
console.log(`尝试调用receiveStorageValue (第${retries + 1}次)`, this.$refs.socketRef);
if (this.$refs.socketRef && typeof this.$refs.socketRef.receiveStorageValue === 'function') {
console.log('成功调用receiveStorageValue方法');
this.$refs.socketRef.receiveStorageValue(value);
} else {
if (retries < maxRetries) {
retries++;
const delay = initialDelay * Math.pow(2, retries - 1); // 退
console.error(`${retries}次尝试失败: socketRef未初始化或receiveStorageValue方法不存在${delay}ms后重试`);
setTimeout(attemptCall, delay);
} else {
console.error(`达到最大重试次数(${maxRetries})调用receiveStorageValue方法失败`);
}
}
};
attemptCall();
}
}
};
@ -150,22 +180,6 @@ export default {
methods: {
initSignalR() {
this.requestStorageValue();
let baseUrl = this.baseUrl;
let url = `http://${baseUrl}/pdaHub`;
//let url = "http://192.168.50.163/pdaHub";
this.signalRUtil = new SignalRUtil(url);
this.signalRUtil
.startConnection()
.then(() => {
this.isSignalRConnected = true;
//
this.signalRUtil.on('Call', (message) => {
this.showSystemAlertAndVibrate(message)
});
})
.catch((error) => {
console.error('SignalR 连接失败:', error);
});
},
stopSignalRConnection() {
if (this.isSignalRConnected && this.signalRUtil) {
@ -208,20 +222,42 @@ export default {
}
// #endif
},
//
requestStorageValue() {
this.$ownerInstance.callMethod('handleGetStorage');
},
//
receiveStorageValue(value) {
console.log('从存储中获取的值:', value);
this.baseUrl = value;
//
requestStorageValue() {
this.$ownerInstance.callMethod('handleGetStorage');
},
//
receiveStorageValue(value) {
console.log('从存储中获取的值:', value);
this.baseUrl = value;
//
}
// baseUrlSignalR
if (this.baseUrl) {
let url = `http://${this.baseUrl}/pdaHub`;
console.log('SignalR 连接 URL:', url);
this.signalRUtil = new SignalRUtil(url);
this.signalRUtil
.startConnection()
.then(() => {
this.isSignalRConnected = true;
//
this.signalRUtil.on('Call', (message) => {
this.showSystemAlertAndVibrate(message)
});
})
.catch((error) => {
console.error('SignalR 连接失败:', error);
});
} else {
console.error('baseUrl为空无法初始化SignalR连接');
}
}
},
async mounted() {
this.initSignalR()
//
setTimeout(() => {
this.initSignalR();
}, 100);
},
}
</script>
@ -250,6 +286,12 @@ view {
margin-top: 10rpx;
}
.menu-icon {
width: 60rpx;
height: 60rpx;
margin-bottom: 8rpx;
}
.grid-item-box {
flex: 1;
/* #ifndef APP-NVUE */
@ -285,10 +327,18 @@ view {
height: 300rpx;
line-height: 300rpx;
}
.menu-icon {
width: 80rpx;
height: 80rpx;
margin-bottom: 8rpx;
}
.card-box {
padding-bottom: 60px;
margin-bottom: 60px;
}
@media screen and (min-width: 500px) {
.uni-swiper-dot-box {
width: 400px;

View File

@ -128,6 +128,8 @@ export default {
if (this.captchaEnabled) {
this.getCode();
}
}).finally(()=>{
this.$modal.closeLoading();
});
},
//

View File

@ -0,0 +1,362 @@
<template>
<view class="container">
<!-- 筛选查询区域 -->
<view class="filter-section">
<uni-forms ref="filterForm" :modelValue="filterData" validateTrigger="bind">
<view class="form-row">
<uni-forms-item label="线别选择" label-width="80" name="lineCode" required class="form-item">
<uni-data-select :localdata="lineOptions" v-model="filterData.lineCode" placeholder="请选择线体" @change="getMRPList"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="选择日期" label-width="80" name="workOrderDate" required class="form-item">
<uni-datetime-picker type="date" v-model="filterData.workOrderDate" format="yyyy-MM-dd" placeholder="请选择日期"></uni-datetime-picker>
</uni-forms-item>
</view>
<view class="btn-search">
<button type="primary" @click="getMRPList">查询</button>
</view>
</uni-forms>
</view>
<!-- 清单展示区域 -->
<view class="list-section">
<view class="list-header">
<text>MRP叫料清单</text>
</view>
<scroll-view scroll-y class="list-container">
<view v-if="mrpList.length === 0" class="empty-tip">
暂无叫料数据
</view>
<view v-for="(item, index) in mrpList" :key="index" class="list-item">
<view class="item-info">
<view class="info-row">
<text class="label">物料名称:</text>
<text class="value">{{ item.materialName }}</text>
</view>
<view class="info-row">
<text class="label">物料号:</text>
<text class="value">{{ item.materialCode }}</text>
</view>
<view class="info-row">
<text class="label">数量:</text>
<text class="value">{{ item.quantity }}</text>
</view>
</view>
<view class="item-action">
<button type="primary" size="mini" @click="callMaterial(item)">叫料</button>
</view>
</view>
</scroll-view>
</view>
<!-- 叫料弹窗 -->
<uni-popup ref="popup" mode="center">
<view class="popup-content">
<view class="popup-header">
<text class="title">叫料确认</text>
</view>
<view class="popup-body">
<view v-if="currentMaterial" class="info-item">
<text class="label">物料名称:</text>
<text class="value">{{ currentMaterial.materialName }}</text>
</view>
<view v-if="currentMaterial" class="info-item">
<text class="label">物料号:</text>
<text class="value">{{ currentMaterial.materialCode }}</text>
</view>
<view v-if="currentMaterial" class="info-item">
<text class="label">可叫数量:</text>
<text class="value">{{ currentMaterial.quantity }}</text>
</view>
<view class="info-item">
<text class="label">叫料数量:</text>
<input type="number" v-model="callQuantity" placeholder="请输入叫料数量" class="input" />
</view>
</view>
<view class="popup-footer">
<button type="default" size="mini" @click="cancelCall">取消</button>
<button type="primary" size="mini" @click="confirmCall">确认</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import { queryCallMaterialMRP,getLineOptions,doLineCallMaterial } from '@/api/mmcall';
export default {
data() {
return {
filterData: {
lineCode: '',
workOrderDate: new Date()
},
lineOptions: [],
mrpList: [],
currentMaterial: null,
callQuantity: 0
};
},
onLoad() {
//
this.filterData.workOrderDate = new Date();
// 线
this.getLineOptions();
},
methods: {
// 线
getLineOptions() {
getLineOptions().then(res => {
if (res.code === 200 && res.data) {
// 线uni-data-select
this.lineOptions = res.data.map(item => ({
text: item.groupName, //
value: item.groupCode //
}));
} else {
this.$modal.showToast('获取线体数据失败');
}
}).catch(err => {
console.error('获取线体数据失败', err);
this.$modal.showToast('获取线体数据失败');
});
},
// MRP
getMRPList() {
if (!this.filterData.lineCode) {
this.$modal.showToast('请先选择线体');
return;
}
//
const params = {
pageNum: 1,
pageSize: 100,
lineCode: this.filterData.lineCode,
workOrderDate: this.$dayjs(this.filterData.workOrderDate).format('YYYY-MM-DD')
};
//
uni.showLoading({
title: '加载中...'
});
// APIMRP
queryCallMaterialMRP(params).then(res => {
uni.hideLoading();
if (res.code === 200 && res.data) {
this.mrpList = res.data.result;
console.log('MRP数据:', res.data.result);
} else {
this.mrpList = [];
this.$modal.showToast(res.message || '获取MRP数据失败');
}
}).catch(err => {
uni.hideLoading();
console.error('获取MRP数据失败', err);
this.mrpList = [];
this.$modal.showToast('获取MRP数据失败');
});
},
//
callMaterial(item) {
//
this.currentMaterial = item;
this.callQuantity = item.quantity;
//
this.$refs.popup.open();
},
//
confirmCall() {
if (!this.currentMaterial) return;
//
const quantity = parseInt(this.callQuantity);
if (isNaN(quantity) || quantity <= 0 || quantity > this.currentMaterial.quantity) {
this.$modal.showToast('请输入有效的叫料数量(大于0且不超过可叫数量)');
return;
}
//
const params = {
id: this.currentMaterial.id, // ID
quantity: quantity, //
lineCode: this.filterData.lineCode, // 线
workOrderDate: this.$dayjs(this.filterData.workOrderDate).format('YYYY-MM-DD') //
};
//
uni.showLoading({
title: '叫料中...'
});
// API
doLineCallMaterial(params).then(res => {
uni.hideLoading();
if (res.code === 200) {
this.$modal.showToast(`成功叫料 ${quantity}${this.currentMaterial.materialName}`);
//
this.currentMaterial.quantity -= quantity;
// 0
if (this.currentMaterial.quantity <= 0) {
this.mrpList = this.mrpList.filter(m => m.id !== this.currentMaterial.id);
}
//
this.$refs.popup.close();
} else {
this.$modal.showToast(res.message || '叫料失败');
}
}).catch(err => {
uni.hideLoading();
console.error('叫料失败', err);
this.$modal.showToast('叫料失败');
});
},
//
cancelCall() {
this.$refs.popup.close();
}
}
};
</script>
<style scoped>
.container {
padding: 20rpx;
}
.header {
text-align: center;
padding: 20rpx 0;
margin-bottom: 20rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.filter-section {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.form-row {
display: flex;
flex-direction: column;
gap: 20rpx;
padding: 10rpx 0;
}
.form-item {
width: 100%;
}
.uni-forms-item__label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.btn-search {
margin-top: 20rpx;
}
.list-section {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.list-header {
padding: 10rpx 0;
border-bottom: 1rpx solid #eee;
margin-bottom: 10rpx;
}
.list-header text {
font-size: 32rpx;
font-weight: bold;
}
.list-container {
height: 500rpx;
}
.list-item {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
}
.item-info {
flex: 1;
}
.info-row {
display: flex;
margin-bottom: 10rpx;
}
.label {
width: 120rpx;
color: #999;
}
.value {
flex: 1;
}
.item-action {
display: flex;
align-items: center;
}
.empty-tip {
text-align: center;
padding: 40rpx 0;
color: #999;
}
/* 弹窗样式 */
.popup-content {
width: 80%;
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx;
}
.popup-header {
padding: 10rpx 0;
border-bottom: 1rpx solid #eee;
margin-bottom: 20rpx;
}
.popup-header .title {
font-size: 32rpx;
font-weight: bold;
}
.popup-body {
padding: 10rpx 0;
}
.info-item {
display: flex;
margin-bottom: 20rpx;
align-items: center;
}
.info-item .label {
width: 120rpx;
color: #999;
}
.info-item .value {
flex: 1;
}
.info-item .input {
flex: 1;
border: 1rpx solid #ccc;
padding: 10rpx;
border-radius: 8rpx;
}
.popup-footer {
display: flex;
justify-content: space-around;
margin-top: 20rpx;
}
.popup-footer button {
width: 35%;
}
</style>

View File

@ -0,0 +1,249 @@
<template>
<view class="container">
<!-- 筛选查询区域 -->
<view class="filter-section">
<uni-forms ref="filterForm" :modelValue="filterData" validateTrigger="bind">
<view class="form-row">
<uni-forms-item label="线别选择" label-width="80" name="lineCode" required class="form-item">
<uni-data-select :localdata="lineOptions" v-model="filterData.lineCode" placeholder="请选择线体" @change="getReceiveList"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="选择日期" label-width="80" name="workOrderDate" required class="form-item">
<uni-datetime-picker type="date" v-model="filterData.workOrderDate" format="yyyy-MM-dd" placeholder="请选择日期"></uni-datetime-picker>
</uni-forms-item>
</view>
<view class="btn-search">
<button type="primary" @click="getReceiveList">查询</button>
</view>
</uni-forms>
</view>
<!-- 清单展示区域 -->
<view class="list-section">
<view class="list-header">
<text>收料清单</text>
</view>
<scroll-view scroll-y class="list-container">
<view v-if="receiveList.length === 0" class="empty-tip">
暂无收料数据
</view>
<view v-for="(item, index) in receiveList" :key="index" class="list-item">
<view class="item-info">
<view class="info-row">
<text class="label">物料名称:</text>
<text class="value">{{ item.materialName }}</text>
</view>
<view class="info-row">
<text class="label">物料号:</text>
<text class="value">{{ item.materialCode }}</text>
</view>
<view class="info-row">
<text class="label">供应商:</text>
<text class="value">{{ item.supplier }}</text>
</view>
<view class="info-row">
<text class="label">批次号:</text>
<text class="value">{{ item.batchNo }}</text>
</view>
<view class="info-row">
<text class="label">待收数量:</text>
<text class="value">{{ item.waitingQuantity }}</text>
</view>
</view>
<view class="item-actions">
<button type="primary" size="mini" @click="receiveMaterial(item)">收料</button>
<button type="default" size="mini" @click="returnMaterial(item)">退料</button>
</view>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
import { queryReceiveList } from '@/api/mmcall';
export default {
data() {
return {
filterData: {
lineCode: '',
workOrderDate: new Date()
},
lineOptions: [
{ text: 'U03线', value: 'U03' },
{ text: 'U05线', value: 'U05' },
{ text: 'U16线', value: 'U16' },
{ text: 'U17线', value: 'U17' }
],
receiveList: []
};
},
onLoad() {
//
this.filterData.date = new Date();
},
methods: {
//
getReceiveList() {
if (!this.filterData.lineCode) {
this.$modal.showToast('请先选择线体');
return;
}
// API
setTimeout(() => {
//
this.receiveList = [
{
materialName: '底漆-A',
materialCode: 'MAT001',
supplier: '供应商1',
batchNo: 'BATCH001',
waitingQuantity: 100
},
{
materialName: '面漆-B',
materialCode: 'MAT002',
supplier: '供应商2',
batchNo: 'BATCH002',
waitingQuantity: 150
},
{
materialName: '清漆-C',
materialCode: 'MAT003',
supplier: '供应商3',
batchNo: 'BATCH003',
waitingQuantity: 80
}
];
}, 500);
},
//
receiveMaterial(item) {
uni.showModal({
title: '收料确认',
content: `确定要收 ${item.materialName} (${item.materialCode}) 吗?`,
success: (res) => {
if (res.confirm) {
// API
setTimeout(() => {
this.$modal.showToast('收料成功');
//
this.getReceiveList();
}, 500);
}
}
});
},
// 退
returnMaterial(item) {
uni.showModal({
title: '退料确认',
content: `确定要退 ${item.materialName} (${item.materialCode}) 吗?`,
success: (res) => {
if (res.confirm) {
// 退API
setTimeout(() => {
this.$modal.showToast('退料成功');
//
this.getReceiveList();
}, 500);
}
}
});
}
}
};
</script>
<style scoped>
.container {
padding: 20rpx;
}
.header {
text-align: center;
padding: 20rpx 0;
margin-bottom: 20rpx;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.filter-section {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.form-row {
display: flex;
flex-direction: column;
gap: 20rpx;
padding: 10rpx 0;
}
.form-item {
width: 100%;
}
.uni-forms-item__label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.btn-search {
margin-top: 20rpx;
}
.list-section {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.list-header {
padding: 10rpx 0;
border-bottom: 1rpx solid #eee;
margin-bottom: 10rpx;
}
.list-header text {
font-size: 32rpx;
font-weight: bold;
}
.list-container {
height: 500rpx;
}
.list-item {
display: flex;
justify-content: space-between;
padding: 20rpx 0;
border-bottom: 1rpx solid #eee;
}
.item-info {
flex: 1;
}
.info-row {
display: flex;
margin-bottom: 10rpx;
}
.label {
width: 120rpx;
color: #999;
}
.value {
flex: 1;
}
.item-actions {
display: flex;
flex-direction: column;
gap: 10rpx;
}
.empty-tip {
text-align: center;
padding: 40rpx 0;
color: #999;
}
</style>

View File

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<defs>
<linearGradient id="arrowGradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#4A6CF7;stop-opacity:1" />
<stop offset="100%" style="stop-color:#1E3AFA;stop-opacity:1" />
</linearGradient>
</defs>
<path d="M5 12h14" stroke="url(#arrowGradient)"/>
<path d="m12 5 7 7-7 7" stroke="url(#arrowGradient)"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#F87171"/>
<path d="M30 18C35 18 38 23 38 28C38 33 35 38 30 38C25 38 22 33 22 28C22 23 25 18 30 18Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M30 38V44" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M25 44H35" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M20 35L15 30" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<path d="M40 35L45 30" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 675 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#22C55E"/>
<path d="M20 20H40V40H20V20Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M25 20V40" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M20 25H40" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M35 28L43 20" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 555 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#8B5CF6"/>
<path d="M25 20L35 20V35L25 35Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M35 20L42 20" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M35 25L42 25" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M18 35L18 42" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M23 42L13 42" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 624 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#EC4899"/>
<path d="M25 20L35 20V35L25 35Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18 20L25 20" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M18 25L25 25" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M35 35L35 42" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
<path d="M28 42L42 42" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 624 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#4A6CF7"/>
<path d="M25 18L35 18L35 40L25 40Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 25L40 25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M20 30L35 30" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M35 18L42 12" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 539 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#FB923C"/>
<path d="M25 18L35 18L35 40L25 40Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 25L40 25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M20 30L35 30" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M35 18L42 12" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 539 B

View File

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="60" viewBox="0 0 60 60" fill="none">
<rect x="5" y="5" width="50" height="50" rx="12" fill="#4ADE80"/>
<path d="M25 18L35 18L35 40L25 40Z" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M20 25L40 25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M20 30L35 30" stroke="white" stroke-width="2" stroke-linecap="round"/>
<path d="M35 18L42 12" stroke="white" stroke-width="2.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 539 B

View File

@ -46,6 +46,11 @@ const request = config => {
// console.log('response',response);
let [error, res] = response
if (error) {
if(error.errMsg === "request:fail abort statusCode:-1 timeout"){
toast('接口连接超时请检查IP地址')
reject(error)
return
}
toast('后端接口连接异常')
reject(error)
return