调整部分前端布局和后端增删改逻辑

This commit is contained in:
焦龙言
2026-09-28 18:29:10 +08:00
parent 17d991a74a
commit a539b4eb71
57 changed files with 87382 additions and 895 deletions
+320 -311
View File
@@ -1,231 +1,62 @@
<template>
<view class="flex h-full flex-col bg-gray-50 overflow-hidden">
<scroll-view scroll-y class="flex-1" :show-scrollbar="false">
<view class="p-4 pb-24 space-y-6">
<view class="work-page">
<scroll-view
class="work-scroll"
scroll-y
:show-scrollbar="false"
>
<view class="work-content">
<view class="work-heading">
<view class="work-heading-copy">
<text class="work-kicker">业务工作台</text>
<text class="work-subtitle">
根据当前账号权限,快速进入现场业务流程
</text>
</view>
<view class="work-permission-count">
<text class="work-permission-value">{{ visibleBusinessEntries.length }}</text>
<text class="work-permission-label">项可用</text>
</view>
</view>
<TestBatchModeSwitch />
<!-- Banner -->
<view
class="relative h-40 w-full overflow-hidden rounded-2xl shadow-lg shadow-indigo-100"
>
<swiper
class="h-40 w-full"
:current="swiperDotIndex"
@change="changeSwiper"
autoplay
interval="3000"
circular
>
<swiper-item v-for="(item, index) in data" :key="index">
<view class="h-full w-full" @click="clickBannerItem(item)">
<image
:src="item.image"
mode="scaleToFill"
class="block h-full w-full"
/>
</view>
</swiper-item>
</swiper>
<!-- Custom Dots -->
<view
class="absolute bottom-3 right-0 left-0 flex justify-center space-x-2 pointer-events-none"
>
<view
v-for="(item, index) in data"
:key="index"
class="h-1.5 rounded-full transition-all duration-300"
:class="current === index ? 'bg-white w-4' : 'bg-white/50 w-1.5'"
>
<view class="work-section">
<view class="work-section-header">
<view class="work-section-marker"></view>
<view class="work-section-copy">
<text class="work-section-title">业务管理</text>
<text class="work-section-description">选择需要执行的现场流程</text>
</view>
</view>
</view>
<!-- AI Tools Section -->
<view>
<view class="mb-4 flex items-center space-x-2">
<view class="h-4 w-1 rounded-full bg-indigo-500"></view>
<text class="text-base font-bold text-gray-800">AI 生产力</text>
</view>
<view class="grid grid-cols-2 gap-4">
<view v-if="visibleBusinessEntries.length" class="work-entry-list">
<view
class="group relative overflow-hidden rounded-2xl bg-white p-5 shadow-sm transition-all active:scale-95"
@click="handleToAiChat"
v-for="entry in visibleBusinessEntries"
:key="entry.path"
class="work-entry"
@click="handleBusinessEntry(entry)"
>
<view
class="absolute -right-4 -top-4 size-20 rounded-full bg-indigo-50 opacity-50"
></view>
<view class="relative z-10 flex flex-col">
<view
class="mb-3 flex size-10 items-center justify-center rounded-xl bg-indigo-500 text-white shadow-md shadow-indigo-200"
>
<view class="i-mdi-chat text-xl"></view>
</view>
<text class="font-bold text-gray-800">智能对话</text>
<text class="mt-1 text-xs text-gray-500">智能助手</text>
class="work-entry-icon"
:class="entry.iconClass"
>
<view :class="entry.icon" class="work-entry-icon-glyph"></view>
</view>
</view>
<view
class="group relative overflow-hidden rounded-2xl bg-white p-5 shadow-sm transition-all active:scale-95"
@click="handleBuilding"
>
<view
class="absolute -right-4 -top-4 size-20 rounded-full bg-purple-50 opacity-50"
></view>
<view class="relative z-10 flex flex-col">
<view
class="mb-3 flex size-10 items-center justify-center rounded-xl bg-purple-500 text-white shadow-md shadow-purple-200"
>
<view class="i-mdi-image-multiple text-xl"></view>
</view>
<text class="font-bold text-gray-800">图像生成</text>
<text class="mt-1 text-xs text-gray-500">创意工坊</text>
<view class="work-entry-copy">
<text class="work-entry-title">{{ entry.title }}</text>
<text class="work-entry-description">{{ entry.description }}</text>
</view>
<view class="i-mdi-chevron-right work-entry-arrow"></view>
</view>
</view>
</view>
<!-- PDA Business Section -->
<view v-if="visibleBusinessEntries.length">
<view class="mb-4 flex items-center space-x-2">
<view class="h-4 w-1 rounded-full bg-emerald-500"></view>
<text class="text-base font-bold text-gray-800">现场业务</text>
</view>
<view class="rounded-2xl bg-white p-5 shadow-sm">
<view class="grid grid-cols-3 gap-4">
<view
v-for="entry in visibleBusinessEntries"
:key="entry.path"
class="flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBusinessEntry(entry)"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-emerald-50 text-emerald-600"
>
<view :class="entry.icon" class="text-xl"></view>
</view>
<text class="text-center text-[11px] font-medium text-gray-600">
{{ entry.title }}
</text>
<text class="text-center text-[10px] text-gray-400">
{{ entry.description }}
</text>
</view>
</view>
</view>
</view>
<!-- System Management Section -->
<view>
<view class="mb-4 flex items-center space-x-2">
<view class="h-4 w-1 rounded-full bg-blue-500"></view>
<text class="text-base font-bold text-gray-800">系统管理</text>
</view>
<view class="rounded-2xl bg-white p-5 shadow-sm">
<view class="flex flex-wrap justify-between gap-y-4">
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleToUserList"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-blue-50 text-blue-500 transition-colors group-active:bg-blue-100"
>
<view class="i-mdi-account text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>用户管理</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-orange-50 text-orange-500 transition-colors group-active:bg-orange-100"
>
<view class="i-mdi-badge-account text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>角色管理</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-green-50 text-green-500 transition-colors group-active:bg-green-100"
>
<view class="i-mdi-office-building text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>部门管理</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-red-50 text-red-500 transition-colors group-active:bg-red-100"
>
<view class="i-mdi-cog text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>配置管理</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-cyan-50 text-cyan-500 transition-colors group-active:bg-cyan-100"
>
<view class="i-mdi-book-open-page-variant text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>字典管理</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-yellow-50 text-yellow-500 transition-colors group-active:bg-yellow-100"
>
<view class="i-mdi-bullhorn text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>通知公告</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-pink-50 text-pink-500 transition-colors group-active:bg-pink-100"
>
<view class="i-mdi-file-document-outline text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600"
>日志管理</text
>
</view>
<view
class="w-[22%] flex flex-col items-center space-y-1.5 active:opacity-60"
@click="handleBuilding"
>
<view
class="flex size-10 items-center justify-center rounded-xl bg-gray-50 text-gray-500 transition-colors group-active:bg-gray-100"
>
<view class="i-mdi-dots-horizontal text-xl"></view>
</view>
<text class="text-[11px] font-medium text-gray-600">更多</text>
</view>
<view v-else class="work-empty-state">
<view class="work-empty-icon">
<view class="i-mdi-lock-outline work-empty-icon-glyph"></view>
</view>
<text class="work-empty-title">暂无已授权业务</text>
<text class="work-empty-description">请联系管理员分配业务菜单权限</text>
</view>
</view>
</view>
@@ -234,113 +65,291 @@
</template>
<script setup>
import { computed, ref, getCurrentInstance } from "vue";
import { computed, getCurrentInstance } from "vue";
import TestBatchModeSwitch from "@/components/business/TestBatchModeSwitch.vue";
import { businessMenuEntries } from "@/config/businessMenu";
const { proxy } = getCurrentInstance();
const current = ref(0);
const swiperDotIndex = ref(0);
const data = ref([
{ image: "/static/images/banner/banner01.jpg" },
{ image: "/static/images/banner/banner02.jpg" },
{ image: "/static/images/banner/banner03.jpg" },
]);
const businessEntries = [
{
path: "/pages/business/inbound/index",
title: "仓库入库",
description: "扫描托盘登记入库",
icon: "i-mdi-package-down",
color: "blue",
permissions: [
"business:inbound:list",
"business:inbound:query",
"business:inbound:add",
"business:inbound:edit",
"business:inbound:confirm",
],
},
{
path: "/pages/business/filling/index",
title: "托盘装填",
description: "录入菌种和包数",
icon: "i-mdi-package-variant-closed-plus",
color: "green",
permissions: [
"business:filling:list",
"business:filling:query",
"business:filling:add",
],
},
{
path: "/pages/business/shipment/index",
title: "发货出库",
description: "扫码创建发货单",
icon: "i-mdi-truck-delivery",
color: "orange",
permissions: [
"business:shipment:list",
"business:shipment:query",
"business:shipment:add",
"business:shipment:edit",
"business:shipment:confirm",
],
},
{
path: "/pages/business/usage/index",
title: "现场使用",
description: "绑定产线记录消耗",
icon: "i-mdi-factory",
color: "purple",
permissions: [
"business:usage:list",
"business:usage:query",
"business:usage:add",
],
},
{
path: "/pages/business/return/index",
title: "退回仓库",
description: "申请和确认退回",
icon: "i-mdi-undo-variant",
color: "red",
permissions: [
"business:return:list",
"business:return:query",
"business:return:request",
"business:return:confirm",
],
},
];
const visibleBusinessEntries = computed(() =>
businessEntries.filter((entry) => proxy.$auth.hasPermiOr(entry.permissions)),
businessMenuEntries.filter((entry) => proxy.$auth.hasPermi(entry.permission)),
);
function clickBannerItem(item) {
console.info(item);
}
function changeSwiper(e) {
current.value = e.detail.current;
}
function handleToAiChat() {
handleBuilding();
}
function handleToUserList() {
handleBuilding();
}
function handleBusinessEntry(entry) {
if (!proxy.$auth.hasPermiOr(entry.permissions)) {
proxy.$modal.msgError("当前账号没有该业务权限");
if (!proxy.$auth.hasPermi(entry.permission)) {
proxy.$modal.msgError("当前账号没有该业务菜单权限");
return;
}
proxy.$tab.navigateTo(entry.path);
}
function handleBuilding() {
proxy.$modal.msg("模块建设中~");
}
</script>
<style lang="scss" scoped>
.work-page {
display: flex;
width: 100%;
height: 100%;
min-width: 0;
flex-direction: column;
overflow-x: hidden;
background: #f4f8f8;
}
.work-scroll {
width: 100%;
min-width: 0;
flex: 1;
}
.work-content {
width: 100%;
min-width: 0;
box-sizing: border-box;
padding: 24rpx 28rpx calc(140rpx + env(safe-area-inset-bottom));
}
.work-heading {
display: flex;
min-width: 0;
align-items: flex-start;
justify-content: space-between;
gap: 18rpx;
margin-bottom: 20rpx;
}
.work-heading-copy {
min-width: 0;
flex: 1;
}
.work-kicker {
display: block;
color: #28225c;
font-size: 38rpx;
font-weight: 700;
line-height: 1.3;
}
.work-subtitle {
display: block;
margin-top: 10rpx;
color: #6c7786;
font-size: 24rpx;
line-height: 1.55;
overflow-wrap: anywhere;
}
.work-permission-count {
display: flex;
flex: 0 0 auto;
align-items: baseline;
border-radius: 14rpx;
padding: 12rpx 16rpx;
background: #e9f7f6;
color: #008596;
flex-direction: column;
text-align: right;
}
.work-permission-value {
font-size: 34rpx;
font-weight: 700;
line-height: 1.1;
}
.work-permission-label {
margin-top: 4rpx;
font-size: 20rpx;
line-height: 1.2;
}
.work-section {
width: 100%;
min-width: 0;
box-sizing: border-box;
margin-top: 20rpx;
border-radius: 20rpx;
padding: 24rpx;
background: #ffffff;
box-shadow: 0 8rpx 24rpx rgba(40, 34, 92, 0.06);
}
.work-section-header {
display: flex;
min-width: 0;
align-items: flex-start;
gap: 14rpx;
}
.work-section-marker {
width: 8rpx;
height: 38rpx;
flex: 0 0 8rpx;
border-radius: 999rpx;
background: #008596;
}
.work-section-copy {
min-width: 0;
flex: 1;
}
.work-section-title {
display: block;
color: #28225c;
font-size: 30rpx;
font-weight: 700;
line-height: 1.35;
}
.work-section-description {
display: block;
margin-top: 6rpx;
color: #8b969d;
font-size: 22rpx;
line-height: 1.5;
}
.work-entry-list {
display: flex;
min-width: 0;
margin-top: 20rpx;
gap: 12rpx;
flex-direction: column;
}
.work-entry {
display: flex;
width: 100%;
min-width: 0;
box-sizing: border-box;
align-items: center;
gap: 16rpx;
border: 1rpx solid #e5eeee;
border-radius: 16rpx;
padding: 18rpx;
background: #fbfdfd;
}
.work-entry:active {
border-color: #8ccbc5;
background: #f0faf9;
}
.work-entry-icon {
display: flex;
width: 82rpx;
height: 82rpx;
flex: 0 0 82rpx;
align-items: center;
justify-content: center;
border-radius: 18rpx;
}
.work-entry-icon-glyph {
font-size: 42rpx;
}
.work-entry-copy {
min-width: 0;
flex: 1;
}
.work-entry-title,
.work-entry-description {
display: block;
min-width: 0;
overflow-wrap: anywhere;
word-break: break-word;
}
.work-entry-title {
color: #27313a;
font-size: 27rpx;
font-weight: 700;
line-height: 1.4;
}
.work-entry-description {
margin-top: 7rpx;
color: #7b8791;
font-size: 22rpx;
line-height: 1.5;
}
.work-entry-arrow {
flex: 0 0 34rpx;
color: #a9b7bb;
font-size: 34rpx;
}
.work-empty-state {
display: flex;
align-items: center;
padding: 70rpx 16rpx 54rpx;
flex-direction: column;
text-align: center;
}
.work-empty-icon {
display: flex;
width: 84rpx;
height: 84rpx;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #f1f5f5;
color: #9aa5ad;
}
.work-empty-icon-glyph {
font-size: 42rpx;
}
.work-empty-title {
display: block;
margin-top: 20rpx;
color: #4b5563;
font-size: 26rpx;
font-weight: 600;
}
.work-empty-description {
display: block;
margin-top: 8rpx;
color: #9aa5ad;
font-size: 22rpx;
line-height: 1.5;
overflow-wrap: anywhere;
}
@media screen and (max-width: 420px) {
.work-content {
padding-right: 20rpx;
padding-left: 20rpx;
}
.work-kicker {
font-size: 34rpx;
}
.work-section {
padding: 20rpx;
}
.work-entry {
gap: 12rpx;
padding: 14rpx;
}
.work-entry-icon {
width: 72rpx;
height: 72rpx;
flex-basis: 72rpx;
}
.work-entry-icon-glyph {
font-size: 36rpx;
}
}
</style>