feat: 完成订单履约菜单重构与业务优化
1. 调整token有效期从30分钟改为60分钟 2. 重构订单履约菜单结构,拆分出供应商履约子目录 3. 修复发货单状态校验逻辑,允许confirmed状态发货 4. 调整页面表格样式与列宽适配 5. 新增供应商履约相关路由与菜单权限 6. 替换首页仪表盘为福安德平台首页 7. 新增批量客户初始化SQL与重复菜单清理脚本 8. 移除顶部导航栏的源码和文档地址入口
This commit is contained in:
@@ -123,8 +123,8 @@ token:
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
# 令牌有效期(默认60分钟)
|
||||
expireTime: 60
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
|
||||
@@ -98,7 +98,7 @@ public class BizDeliveryOrderServiceImpl implements IBizDeliveryOrderService {
|
||||
public int ship(Long id) {
|
||||
BizDeliveryOrder d = mapper.selectBizDeliveryOrderById(id);
|
||||
if (d == null) throw new RuntimeException("发货单不存在");
|
||||
if (!"pending".equals(d.getDeliveryStatus()))
|
||||
if (!"pending".equals(d.getDeliveryStatus()) && !"confirmed".equals(d.getDeliveryStatus()))
|
||||
throw new RuntimeException("当前状态不允许发货确认");
|
||||
return mapper.updateDeliveryStatus(id, "transit", null, null, "");
|
||||
}
|
||||
|
||||
@@ -435,12 +435,12 @@ body {
|
||||
|
||||
/* 小按钮紧凑 */
|
||||
.el-button--mini {
|
||||
padding: 5px 10px !important;
|
||||
padding: 4px 7px !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.el-button--small {
|
||||
padding: 7px 12px !important;
|
||||
padding: 6px 10px !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
@@ -451,7 +451,6 @@ body {
|
||||
border: 1px solid var(--border-gray) !important;
|
||||
border-bottom: none !important;
|
||||
font-size: 12px !important;
|
||||
table-layout: fixed !important;
|
||||
|
||||
/* 表头 */
|
||||
thead th {
|
||||
@@ -470,21 +469,21 @@ body {
|
||||
td {
|
||||
color: var(--text-dark) !important;
|
||||
font-size: 12px !important;
|
||||
padding: 4px 6px !important;
|
||||
padding: 3px 4px !important;
|
||||
border-bottom: 1px solid var(--border-light) !important;
|
||||
white-space: nowrap !important;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
}
|
||||
|
||||
/* cell 内部无换行 */
|
||||
/* cell 内部(操作列允许换行) */
|
||||
.cell {
|
||||
white-space: nowrap !important;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
line-height: 1.4 !important;
|
||||
padding-left: 2px !important;
|
||||
padding-right: 2px !important;
|
||||
line-height: 1.3 !important;
|
||||
padding-left: 1px !important;
|
||||
padding-right: 1px !important;
|
||||
}
|
||||
|
||||
/* 行悬停 */
|
||||
|
||||
@@ -12,14 +12,6 @@
|
||||
<template v-if="device!=='mobile'">
|
||||
<search id="header-search" class="right-menu-item" />
|
||||
|
||||
<el-tooltip content="源码地址" effect="dark" placement="bottom">
|
||||
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="文档地址" effect="dark" placement="bottom">
|
||||
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
|
||||
</el-tooltip>
|
||||
|
||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
||||
|
||||
<el-tooltip content="布局大小" effect="dark" placement="bottom">
|
||||
|
||||
@@ -189,50 +189,51 @@ export const dynamicRoutes = [
|
||||
}]
|
||||
},
|
||||
|
||||
// ── 订单履约 ──
|
||||
// ── 订单履约(供应商履约) ──
|
||||
{
|
||||
path: '/bid/order/pending',
|
||||
path: '/bid/order',
|
||||
component: Layout,
|
||||
permissions: ['bid:order:pending'],
|
||||
children: [{
|
||||
path: '',
|
||||
component: () => import('@/views/bid/order/pending'),
|
||||
name: 'OrderPending',
|
||||
meta: { title: '待发订单', activeMenu: '/bid/order' }
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/bid/order/transit',
|
||||
component: Layout,
|
||||
permissions: ['bid:order:transit'],
|
||||
children: [{
|
||||
path: '',
|
||||
component: () => import('@/views/bid/order/transit'),
|
||||
name: 'OrderTransit',
|
||||
meta: { title: '在途订单', activeMenu: '/bid/order' }
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/bid/order/history',
|
||||
component: Layout,
|
||||
permissions: ['bid:order:history'],
|
||||
children: [{
|
||||
path: '',
|
||||
component: () => import('@/views/bid/order/history'),
|
||||
name: 'OrderHistory',
|
||||
meta: { title: '历史订单', activeMenu: '/bid/order' }
|
||||
}]
|
||||
},
|
||||
{
|
||||
path: '/bid/order/closeDate',
|
||||
component: Layout,
|
||||
permissions: ['bid:order:closeDate'],
|
||||
children: [{
|
||||
path: '',
|
||||
component: () => import('@/views/bid/order/closeDate'),
|
||||
name: 'CloseDate',
|
||||
meta: { title: '结单时间管理', activeMenu: '/bid/order' }
|
||||
}]
|
||||
redirect: '/bid/order/pending',
|
||||
alwaysShow: true,
|
||||
hidden: true,
|
||||
meta: { title: '供应商履约' },
|
||||
children: [
|
||||
{
|
||||
path: 'pending',
|
||||
component: () => import('@/views/bid/order/pending'),
|
||||
name: 'OrderPending',
|
||||
permissions: ['bid:order:pending'],
|
||||
meta: { title: '待发订单', activeMenu: '/bid/order' }
|
||||
},
|
||||
{
|
||||
path: 'transit',
|
||||
component: () => import('@/views/bid/order/transit'),
|
||||
name: 'OrderTransit',
|
||||
permissions: ['bid:order:transit'],
|
||||
meta: { title: '在途订单', activeMenu: '/bid/order' }
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
component: () => import('@/views/bid/order/history'),
|
||||
name: 'OrderHistory',
|
||||
permissions: ['bid:order:history'],
|
||||
meta: { title: '历史订单', activeMenu: '/bid/order' }
|
||||
},
|
||||
{
|
||||
path: 'closeDate',
|
||||
component: () => import('@/views/bid/order/closeDate'),
|
||||
name: 'CloseDate',
|
||||
permissions: ['bid:order:closeDate'],
|
||||
meta: { title: '结单时间管理', activeMenu: '/bid/order' }
|
||||
},
|
||||
{
|
||||
path: 'objection',
|
||||
component: () => import('@/views/bid/objection/index'),
|
||||
name: 'OrderObjection',
|
||||
permissions: ['bid:objection:list'],
|
||||
meta: { title: '订单异议', activeMenu: '/bid/order' }
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
// ── 操作记录 ──
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<el-button size="mini" type="text" style="color:#E6A23C" @click="handleSubmitApproval(s.row)" v-if="s.row.deliveryStatus==='pending' || s.row.deliveryStatus==='rejected'">提交审批</el-button>
|
||||
<el-button size="mini" type="text" style="color:#67C23A" @click="handleApprove(s.row)" v-if="s.row.deliveryStatus==='10'">通过</el-button>
|
||||
<el-button size="mini" type="text" style="color:#F56C6C" @click="handleReject(s.row)" v-if="s.row.deliveryStatus==='10'">驳回</el-button>
|
||||
<el-button size="mini" type="text" style="color:#67C23A" @click="handleShip(s.row)" v-if="s.row.deliveryStatus==='pending' || s.row.deliveryStatus==='confirmed'">发货确认</el-button>
|
||||
<el-button size="mini" type="text" style="color:#67C23A" @click="handleShip(s.row)" v-if="s.row.deliveryStatus==='confirmed'">发货确认</el-button>
|
||||
<el-button size="mini" type="text" style="color:#f56c6c" @click="handleDelete(s.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
}},
|
||||
created() { this.getList() },
|
||||
methods: {
|
||||
getList() { this.loading=true; listDelivery(this.q).then(r=>{this.list=(r.rows||[]).map(d=>({...d,deliveryDate:d.deliveryDate?d.deliveryDate.substring(0,10):''}));this.total=r.total||0;this.loading=false}).catch(()=>{this.loading=false}) },
|
||||
getList() { this.loading=true; listDelivery(this.q).then(r=>{const all=r.rows||[];const filtered=all.filter(d=>d.deliveryStatus!=='transit'&&d.deliveryStatus!=='history');this.list=filtered.map(d=>({...d,deliveryDate:d.deliveryDate?d.deliveryDate.substring(0,10):''}));this.total=filtered.length;this.loading=false}).catch(()=>{this.loading=false}) },
|
||||
search() { this.q.pageNum=1; this.getList() }, resetSearch() { this.q.doNo=""; this.q.clientName=""; this.search() },
|
||||
handleView(row) { getDelivery(row.doId).then(r=>{this.detailData=r.data;this.detailOpen=true}).catch(()=>{}) },
|
||||
handleShip(row) { this.$modal.confirm("确认发货?").then(()=>shipDelivery(row.doId)).then(()=>{this.$modal.msgSuccess("已发货");this.getList()}).catch(()=>{}) },
|
||||
|
||||
@@ -38,27 +38,27 @@
|
||||
<!-- ═══ 订单表格 ═══ -->
|
||||
<div class="jd-table-wrap">
|
||||
<el-table v-loading="loading" :data="list" border stripe size="small" class="jd-table" style="width:100%">
|
||||
<el-table-column label="发货单号" width="155">
|
||||
<el-table-column label="发货单号" width="115">
|
||||
<template slot-scope="s">
|
||||
<span class="order-link" @click="handleView(s.row)">{{ s.row.doNo }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="120" align="right">
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="85" align="right">
|
||||
<template slot-scope="s"><span class="amount">¥{{ s.row.totalAmount }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="交货期" prop="deliveryDate" width="95" align="center" />
|
||||
<el-table-column label="收货" prop="actualCloseDate" width="95" align="center" />
|
||||
<el-table-column label="交期差异" width="100" align="center">
|
||||
<el-table-column label="交货期" prop="deliveryDate" width="85" align="center" />
|
||||
<el-table-column label="收货" prop="actualCloseDate" width="85" align="center" />
|
||||
<el-table-column label="交期差异" width="80" align="center">
|
||||
<template slot-scope="s"><span :class="diffClass(s.row)">{{ diffLabel(s.row) }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物料" prop="itemCount" width="55" align="center" />
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<el-table-column label="物料" prop="itemCount" width="50" align="center" />
|
||||
<el-table-column label="状态" width="70" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-tag :type="tagType(s.row)" size="small" effect="dark">{{ tagLabel(s.row) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="170" align="center">
|
||||
<el-table-column label="操作" width="210" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-button size="mini" type="text" @click="handleView(s.row)">详情</el-button>
|
||||
<el-button size="mini" type="text" @click="handleReOrder(s.row)">再次下单</el-button>
|
||||
|
||||
@@ -26,23 +26,23 @@
|
||||
<!-- ═══ 订单表格 ═══ -->
|
||||
<div class="jd-table-wrap">
|
||||
<el-table v-loading="loading" :data="list" border stripe size="small" class="jd-table" style="width:100%">
|
||||
<el-table-column label="发货单号" width="155">
|
||||
<el-table-column label="发货单号" width="115">
|
||||
<template slot-scope="s">
|
||||
<span class="order-link" @click="handleView(s.row)">{{ s.row.doNo }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="120" align="right">
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="85" align="right">
|
||||
<template slot-scope="s"><span class="amount">¥{{ s.row.totalAmount }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="交货期" prop="deliveryDate" width="95" align="center" />
|
||||
<el-table-column label="延期" prop="delayDate" width="90" align="center">
|
||||
<el-table-column label="交货期" prop="deliveryDate" width="85" align="center" />
|
||||
<el-table-column label="延期" prop="delayDate" width="80" align="center">
|
||||
<template slot-scope="s">{{ s.row.delayDate || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="逾期" width="100" align="center">
|
||||
<el-table-column label="逾期" width="80" align="center">
|
||||
<template slot-scope="s"><span v-html="getUrgentBadge(s.row)" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物料" prop="itemCount" width="55" align="center" />
|
||||
<el-table-column label="物料" prop="itemCount" width="50" align="center" />
|
||||
<el-table-column label="操作" width="210" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-button size="mini" type="text" @click="handleView(s.row)">详情</el-button>
|
||||
|
||||
@@ -54,31 +54,31 @@
|
||||
<!-- ═══ 订单表格 ═══ -->
|
||||
<div class="jd-table-wrap">
|
||||
<el-table v-loading="loading" :data="list" border stripe size="small" class="jd-table" style="width:100%">
|
||||
<el-table-column label="发货单号" width="155">
|
||||
<el-table-column label="发货单号" width="115">
|
||||
<template slot-scope="s">
|
||||
<span class="order-link" @click="handleView(s.row)">{{ s.row.doNo }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="120" align="right">
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column label="金额" width="85" align="right">
|
||||
<template slot-scope="s"><span class="amount">¥{{ s.row.totalAmount }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="交货期" width="95" align="center">
|
||||
<el-table-column label="交货期" width="85" align="center">
|
||||
<template slot-scope="s"><span :class="getUrgentClass(s.row)">{{ s.row.deliveryDate }}</span></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="延期至" prop="delayDate" width="90" align="center">
|
||||
<el-table-column label="延期至" prop="delayDate" width="80" align="center">
|
||||
<template slot-scope="s">{{ s.row.delayDate || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="逾期" width="90" align="center">
|
||||
<el-table-column label="逾期" width="80" align="center">
|
||||
<template slot-scope="s"><span v-html="getUrgentBadge(s.row)" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物料" prop="itemCount" width="55" align="center" />
|
||||
<el-table-column label="状态" width="85" align="center">
|
||||
<el-table-column label="物料" prop="itemCount" width="50" align="center" />
|
||||
<el-table-column label="状态" width="70" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-tag :type="transitTagType(s.row)" size="small" effect="dark">{{ transitStatusLabel(s.row) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center">
|
||||
<el-table-column label="操作" width="230" align="center">
|
||||
<template slot-scope="s">
|
||||
<el-button size="mini" type="text" @click="handleView(s.row)">详情</el-button>
|
||||
<el-button size="mini" type="text" style="color:#67C23A" @click="handleComplete(s.row)">收货完成</el-button>
|
||||
|
||||
@@ -1,197 +1,242 @@
|
||||
<template>
|
||||
<div class="dashboard">
|
||||
<el-row :gutter="20" class="stat-row">
|
||||
<el-col :xs="12" :sm="6" v-for="item in (isSupplier ? statCards.filter(c => c.key==='rfqs') : statCards)" :key="item.key">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">
|
||||
<i :class="item.icon" />
|
||||
</div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-num">{{ stats[item.key] }}</div>
|
||||
<div class="stat-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="home-page">
|
||||
<!-- Logo -->
|
||||
<div class="logo-section">
|
||||
<div class="logo-box">
|
||||
<img src="@/assets/logo/logo.svg" alt="福安德" class="logo-img">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="24" :lg="14">
|
||||
<el-card class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span><i class="el-icon-document" /> 最近询价单</span>
|
||||
<router-link to="/rfq" class="panel-more">查看全部</router-link>
|
||||
</div>
|
||||
<el-table :data="recentRfqs" size="small" style="width:100%">
|
||||
<el-table-column prop="rfqNo" label="单号" width="160" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="deadline" label="截止日期" width="105" />
|
||||
<el-table-column label="状态" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" :type="rfqStatusType(scope.row.status)">{{ rfqStatusText(scope.row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :lg="10" v-if="!isSupplier">
|
||||
<el-card class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span><i class="el-icon-shopping-cart-full" /> 最近采购单</span>
|
||||
<router-link to="/purchaseorder" class="panel-more">查看全部</router-link>
|
||||
</div>
|
||||
<el-table :data="recentPos" size="small" style="width:100%">
|
||||
<el-table-column prop="poNo" label="单号" width="140" />
|
||||
<el-table-column prop="supplierName" label="供应商" show-overflow-tooltip />
|
||||
<el-table-column label="状态" width="80">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" :type="poStatusType(scope.row.status)">{{ poStatusText(scope.row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 系统名称 -->
|
||||
<div class="title-section">
|
||||
<h1 class="main-title">福安德智慧报价平台</h1>
|
||||
<p class="sub-title">FUANDE SMART QUOTATION PLATFORM</p>
|
||||
</div>
|
||||
|
||||
<el-row :gutter="20" style="margin-top:20px">
|
||||
<el-col :xs="24" :lg="10" v-if="!isSupplier">
|
||||
<el-card class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span><i class="el-icon-s-custom" /> 供应商列表</span>
|
||||
<router-link to="/supplier" class="panel-more">查看全部</router-link>
|
||||
</div>
|
||||
<el-table :data="suppliers" size="small" style="width:100%">
|
||||
<el-table-column prop="supplierName" label="供应商名称" show-overflow-tooltip />
|
||||
<el-table-column prop="contactName" label="联系人" width="90" />
|
||||
<el-table-column label="等级" width="70">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="mini" :type="gradeType(scope.row.grade)">{{ scope.row.grade || 'B' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="24" :lg="14">
|
||||
<el-card class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span><i class="el-icon-magic-stick" /> 快捷操作</span>
|
||||
</div>
|
||||
<div class="quick-actions">
|
||||
<router-link v-for="action in (isSupplier ? supplierQuickActions : quickActions)" :key="action.path" :to="action.path" class="quick-btn">
|
||||
<div class="quick-icon" :style="{ background: action.color + '18', color: action.color }">
|
||||
<i :class="action.icon" />
|
||||
</div>
|
||||
<span>{{ action.label }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- 分隔线 -->
|
||||
<div class="divider"></div>
|
||||
|
||||
<!-- 欢迎语 -->
|
||||
<div class="welcome-section">
|
||||
<p class="welcome-text">{{ greeting }},{{ nickName }}!欢迎回来</p>
|
||||
</div>
|
||||
|
||||
<!-- 时间 -->
|
||||
<div class="time-section">
|
||||
<div class="time-display">{{ currentTime }}</div>
|
||||
<div class="date-display">{{ currentDate }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部标语 -->
|
||||
<div class="slogan-section">
|
||||
<p class="slogan">原料·研发·生产·销售·服务 全产业链数智运营</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listSupplier } from "@/api/bid/supplier"
|
||||
import { listMaterial } from "@/api/bid/material"
|
||||
import { listRfq } from "@/api/bid/rfq"
|
||||
import { listPurchaseorder } from "@/api/bid/purchaseorder"
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: "Dashboard",
|
||||
computed: {
|
||||
...mapGetters(['nickName', 'roles']),
|
||||
isSupplier() {
|
||||
return this.$store.getters.roles && this.$store.getters.roles.includes('supplier');
|
||||
},
|
||||
supplierQuickActions() {
|
||||
return [
|
||||
{ label: "报价请求", icon: "el-icon-document", color: "#e4393c", path: "/rfq" },
|
||||
{ label: "我的报价", icon: "el-icon-money", color: "#67c23a", path: "/quotation" }
|
||||
];
|
||||
return this.roles && this.roles.includes('supplier')
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
stats: { suppliers: 0, materials: 0, rfqs: 0, pos: 0 },
|
||||
recentRfqs: [],
|
||||
recentPos: [],
|
||||
suppliers: [],
|
||||
statCards: [
|
||||
{ key: "suppliers", label: "供应商", icon: "el-icon-s-custom", color: "#e4393c" },
|
||||
{ key: "materials", label: "物料数", icon: "el-icon-goods", color: "#e4393c" },
|
||||
{ key: "rfqs", label: "询价单", icon: "el-icon-document", color: "#e4393c" },
|
||||
{ key: "pos", label: "采购单", icon: "el-icon-shopping-cart-full", color: "#e4393c" }
|
||||
],
|
||||
currentTime: '',
|
||||
currentDate: '',
|
||||
greeting: '',
|
||||
timer: null,
|
||||
quickActions: [
|
||||
{ label: "新建询价单", icon: "el-icon-edit", color: "#e4393c", path: "/rfq" },
|
||||
{ label: "物料管理", icon: "el-icon-goods", color: "#e4393c", path: "/material" },
|
||||
{ label: "智慧比价", icon: "el-icon-data-analysis", color: "#e4393c", path: "/comparison" },
|
||||
{ label: "采购单", icon: "el-icon-shopping-cart-full", color: "#e4393c", path: "/purchaseorder" },
|
||||
{ label: "供应商", icon: "el-icon-s-cooperation", color: "#e4393c", path: "/supplier" },
|
||||
{ label: "供应商评价", icon: "el-icon-star-off", color: "#e4393c", path: "/evaluation" }
|
||||
{ label: '物料管理', icon: 'el-icon-goods', path: '/material' },
|
||||
{ label: '甲方报价', icon: 'el-icon-document-copy', path: '/clientquote' },
|
||||
{ label: '供应商报价', icon: 'el-icon-money', path: '/quotation' },
|
||||
{ label: '订单管理', icon: 'el-icon-s-order', path: '/bid/order/pending' },
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadDashboard()
|
||||
mounted() {
|
||||
this.updateTime()
|
||||
this.timer = setInterval(this.updateTime, 1000)
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
methods: {
|
||||
loadDashboard() {
|
||||
// 供应商只加载自己有权限的RFQ数据
|
||||
if (this.isSupplier) {
|
||||
listRfq({ pageNum: 1, pageSize: 5 }).then(r => {
|
||||
this.recentRfqs = r.rows || []
|
||||
this.stats.rfqs = r.total || 0
|
||||
}).catch(() => {})
|
||||
return
|
||||
}
|
||||
listSupplier({ pageNum: 1, pageSize: 5 }).then(r => {
|
||||
this.suppliers = r.rows || []
|
||||
this.stats.suppliers = r.total || 0
|
||||
}).catch(() => {})
|
||||
listMaterial({ pageNum: 1, pageSize: 1 }).then(r => {
|
||||
this.stats.materials = r.total || 0
|
||||
}).catch(() => {})
|
||||
listRfq({ pageNum: 1, pageSize: 5 }).then(r => {
|
||||
this.recentRfqs = r.rows || []
|
||||
this.stats.rfqs = r.total || 0
|
||||
}).catch(() => {})
|
||||
listPurchaseorder({ pageNum: 1, pageSize: 5 }).then(r => {
|
||||
this.recentPos = r.rows || []
|
||||
this.stats.pos = r.total || 0
|
||||
}).catch(() => {})
|
||||
updateTime() {
|
||||
const now = new Date()
|
||||
this.currentTime = now.toLocaleTimeString('zh-CN', {
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
})
|
||||
this.currentDate = now.toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
weekday: 'long'
|
||||
})
|
||||
this.greeting = this.getGreeting(now.getHours())
|
||||
},
|
||||
rfqStatusType(s) { return ({ draft:"info", published:"warning", "10":"warning", closed:"", completed:"success", awarded:"success", open:"primary", rejected:"danger" })[s] || "info" },
|
||||
rfqStatusText(s) { return ({ draft:"草稿", published:"已发布", "10":"审批中", closed:"已关闭", completed:"已完成", awarded:"已定标", open:"询价中", rejected:"已驳回" })[s] || (s || "-") },
|
||||
poStatusType(s) { return ({ draft:"info", "10":"warning", rejected:"danger", confirmed:"success", delivered:"", closed:"info", disputed:"danger" })[s] || "info" },
|
||||
poStatusText(s) { return ({ draft:"草稿", "10":"审批中", rejected:"已驳回", confirmed:"已确认", delivered:"已交付", closed:"已关闭", disputed:"异议中" })[s] || (s || "-") },
|
||||
gradeType(g) { return g === "A" ? "success" : g === "B" ? "primary" : g === "C" ? "warning" : "info" }
|
||||
getGreeting(hour) {
|
||||
if (hour >= 5 && hour < 12) return '上午好'
|
||||
if (hour >= 12 && hour < 14) return '中午好'
|
||||
if (hour >= 14 && hour < 18) return '下午好'
|
||||
return '晚上好'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard { padding: 20px; background: #f5f7fa; min-height: calc(100vh - 84px); }
|
||||
.stat-row { margin-bottom: 20px !important; }
|
||||
.stat-card {
|
||||
background: #fff; border: 1px solid #e5e5e5; border-radius: 2px;
|
||||
padding: 14px 18px; display: flex; align-items: center; gap: 14px;
|
||||
.home-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: calc(100vh - 84px);
|
||||
background: #ffffff;
|
||||
padding: 40px 20px 24px;
|
||||
}
|
||||
.stat-icon { font-size: 22px; opacity: 0.35; flex-shrink: 0; }
|
||||
.stat-num { font-size: 22px; font-weight: 400; color: #333; line-height: 1.2; }
|
||||
.stat-label { font-size: 12px; color: #999; margin-top: 2px; }
|
||||
.panel-card {
|
||||
border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
::v-deep .el-card__header { padding: 14px 20px; border-bottom: 1px solid #f0f2f5; }
|
||||
|
||||
/* ═══ Logo ═══ */
|
||||
.logo-section {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
font-size: 14px; font-weight: 600; color: #333;
|
||||
i { margin-right: 6px; color: #e4393c; }
|
||||
|
||||
.logo-box {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* ═══ 标题 ═══ */
|
||||
.title-section {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.main-title {
|
||||
font-size: 28px;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.sub-title {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
letter-spacing: 2px;
|
||||
margin: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ═══ 分隔线 ═══ */
|
||||
.divider {
|
||||
width: 60px;
|
||||
height: 2px;
|
||||
background: #e4393c;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* ═══ 欢迎语 ═══ */
|
||||
.welcome-section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.welcome-text {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ═══ 时间 ═══ */
|
||||
.time-section {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-size: 48px;
|
||||
font-weight: 300;
|
||||
color: #e4393c;
|
||||
font-family: 'Roboto Mono', 'Courier New', monospace;
|
||||
letter-spacing: 2px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.date-display {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* ═══ 标语 ═══ */
|
||||
.slogan-section {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.slogan {
|
||||
font-size: 13px;
|
||||
font-weight: 400;
|
||||
color: #cccccc;
|
||||
margin: 0;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* ═══ 快捷入口 ═══ */
|
||||
.quick-section {
|
||||
width: 100%;
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.quick-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.quick-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 16px 8px;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: #e4393c;
|
||||
background: #fff5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.quick-item-icon {
|
||||
font-size: 24px;
|
||||
color: #e4393c;
|
||||
}
|
||||
|
||||
.quick-item-label {
|
||||
font-size: 12px;
|
||||
color: #666666;
|
||||
}
|
||||
.panel-more { font-size: 12px; color: #e4393c; text-decoration: none; }
|
||||
.panel-more:hover { text-decoration: underline; }
|
||||
.quick-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; padding: 4px 0; }
|
||||
.quick-btn { display: flex; flex-direction: column; align-items: center; gap: 8px; text-decoration: none; padding: 16px 8px; border-radius: 8px; transition: background 0.2s; }
|
||||
.quick-btn:hover { background: #f5f7fa; }
|
||||
.quick-btn span { font-size: 13px; color: #4a5568; }
|
||||
.quick-icon { width: 44px; height: 44px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 20px; }
|
||||
</style>
|
||||
|
||||
12
sql/fix_dup_menu.sql
Normal file
12
sql/fix_dup_menu.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- 清理重复的供应商履约菜单
|
||||
-- 旧的 menu_id=2023 是之前从"订单履约"重命名来的,与新的 2121 重复
|
||||
UPDATE sys_menu SET parent_id = 2121 WHERE parent_id = 2023;
|
||||
DELETE FROM sys_role_menu WHERE menu_id = 2023;
|
||||
DELETE FROM sys_menu WHERE menu_id = 2023;
|
||||
|
||||
-- 验证
|
||||
SELECT m.menu_id, m.menu_name, m.parent_id, p.menu_name AS parent_name, m.order_num, m.perms
|
||||
FROM sys_menu m
|
||||
LEFT JOIN sys_menu p ON m.parent_id = p.menu_id
|
||||
WHERE m.parent_id IN (2120, 2121) OR m.menu_id IN (2120, 2121)
|
||||
ORDER BY m.parent_id, m.order_num;
|
||||
43
sql/fix_menu_supplier_fulfill.sql
Normal file
43
sql/fix_menu_supplier_fulfill.sql
Normal file
@@ -0,0 +1,43 @@
|
||||
-- ═══════════════════════════════════════════════════════════
|
||||
-- 菜单重组:订单履约 → 供应商履约(子目录)+ 甲方履约
|
||||
-- 目标结构:
|
||||
-- 订单履约 (2120)
|
||||
-- ├── 供应商履约 (新目录)
|
||||
-- │ ├── 待发订单
|
||||
-- │ ├── 在途订单
|
||||
-- │ ├── 历史订单
|
||||
-- │ ├── 结单时间管理
|
||||
-- │ └── 订单异议
|
||||
-- └── 甲方履约 (2044)
|
||||
-- ├── 甲方待发
|
||||
-- ├── 甲方在途
|
||||
-- └── 甲方历史
|
||||
-- ═══════════════════════════════════════════════════════════
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- 1. 创建「供应商履约」目录菜单(M = 目录),挂在订单履约(2120)下
|
||||
INSERT IGNORE INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time)
|
||||
VALUES (2121, '供应商履约', 2120, 1, 'supplierFulfill', NULL, 1, 0, 'M', '0', '0', '', 'user', 'admin', NOW());
|
||||
|
||||
-- 2. 将 5 个子菜单移到「供应商履约」下
|
||||
UPDATE sys_menu SET parent_id = 2121, order_num = 1 WHERE perms = 'bid:order:pending';
|
||||
UPDATE sys_menu SET parent_id = 2121, order_num = 2 WHERE perms = 'bid:order:transit';
|
||||
UPDATE sys_menu SET parent_id = 2121, order_num = 3 WHERE perms = 'bid:order:history';
|
||||
UPDATE sys_menu SET parent_id = 2121, order_num = 4 WHERE perms = 'bid:order:closeDate';
|
||||
UPDATE sys_menu SET parent_id = 2121, order_num = 5 WHERE perms = 'bid:objection:list';
|
||||
|
||||
-- 3. 甲方履约保持直接挂在订单履约下,排序调整到 2
|
||||
UPDATE sys_menu SET parent_id = 2120, order_num = 2 WHERE perms = 'bid:clientDelivery:list';
|
||||
|
||||
-- 4. 给 admin 角色授权新菜单
|
||||
INSERT IGNORE INTO sys_role_menu(role_id, menu_id)
|
||||
SELECT 1, menu_id FROM sys_menu WHERE menu_id = 2121;
|
||||
|
||||
-- 5. 验证结果
|
||||
SELECT m.menu_id, m.menu_name, m.parent_id, p.menu_name AS parent_name, m.order_num, m.perms
|
||||
FROM sys_menu m
|
||||
LEFT JOIN sys_menu p ON m.parent_id = p.menu_id
|
||||
WHERE m.parent_id IN (2120, 2121)
|
||||
OR m.menu_id IN (2120, 2121)
|
||||
ORDER BY m.parent_id, m.order_num;
|
||||
23
sql/seed_clients.sql
Normal file
23
sql/seed_clients.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
/* ═══════════════════════════════════════════════════
|
||||
甲方客户批量数据(SQL 直接执行)
|
||||
运行方式:用 Navicat / DataGrip / SQLyog 连上数据库执行
|
||||
或者:mysql -h 49.232.154.205 -P 13306 -u root -p ryvue < seed_clients.sql
|
||||
═══════════════════════════════════════════════════ */
|
||||
|
||||
TRUNCATE TABLE biz_client;
|
||||
|
||||
INSERT INTO biz_client (client_no, client_name, contact, phone, email, city, address, grade, source, status, create_time) VALUES
|
||||
('CU-001', '山东福安德信息科技有限公司', '张经理', '0531-88880001', 'zhang@fuande.com', '济南', '山东省济南市高新区齐鲁软件园A座5层', 'A', '直客', '0', NOW()),
|
||||
('CU-002', '青岛海尔智能家电有限公司', '李工', '0532-88990001', 'ligong@haier.com', '青岛', '山东省青岛市海尔路1号海尔工业园', 'A', '招标', '0', NOW()),
|
||||
('CU-003', '烟台万华化学集团股份有限公司', '王主管', '0535-3388001', 'wang@whchem.com', '烟台', '山东省烟台市经济技术开发区万华工业园', 'A', '长期合作', '0', NOW()),
|
||||
('CU-004', '济南二机床集团有限公司', '赵工', '0531-81620001', 'zhao@jier.com', '济南', '山东省济南市市中区机床二厂路4号', 'B', '招标', '0', NOW()),
|
||||
('CU-005', '潍柴动力股份有限公司', '孙部长', '0536-8197001', 'sun@weichai.com', '潍坊', '山东省潍坊市高新区福寿东街197号甲', 'A', '长期合作', '0', NOW()),
|
||||
('CU-006', '山东钢铁集团有限公司', '刘工', '0531-67606001', 'liu@shangang.com', '济南', '山东省济南市历下区工业北路21号', 'B', '招标', '0', NOW()),
|
||||
('CU-007', '中车青岛四方机车车辆股份有限公司', '陈经理', '0532-86088001', 'chen@crrc.com', '青岛', '山东省青岛市城阳区锦宏东路88号', 'A', '战略合作', '0', NOW()),
|
||||
('CU-008', '山东黄金矿业股份有限公司', '黄工', '0535-2099001', 'huang@sd-gold.com', '烟台', '山东省烟台市莱州市金城镇', 'B', '招标', '0', NOW()),
|
||||
('CU-009', '山东魏桥创业集团有限公司', '马主管', '0543-4305001', 'ma@weiqiao.com', '滨州', '山东省滨州市邹平市经济开发区魏纺路12号', 'B', '长期合作', '0', NOW()),
|
||||
('CU-010', '浪潮集团有限公司', '周经理', '0531-85106001', 'zhou@inspur.com', '济南', '山东省济南市高新区浪潮路1036号', 'A', '直客', '0', NOW());
|
||||
|
||||
SELECT CONCAT('已插入 ', COUNT(*), ' 条甲方客户数据') AS result FROM biz_client;
|
||||
|
||||
SELECT CONCAT('已插入 ', COUNT(*), ' 条甲方客户数据') AS result FROM biz_client;
|
||||
Reference in New Issue
Block a user