feat: 新增甲方客户管理模块及配套功能
1. 新增甲方客户CRUD接口、前端页面与权限控制 2. 新增发货单管理模块,包含订单状态流转 3. 修复系统菜单名称乱码问题 4. 新增项目启动脚本与数据库初始化脚本 5. 新增相关实体类、Mapper、Service实现 6. 补充项目设计文档与忽略配置
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -23,6 +23,12 @@ logs/
|
||||
# Spring Boot
|
||||
*.pid
|
||||
|
||||
# Demo / sample projects
|
||||
shipping_system/
|
||||
|
||||
# Design documents (internal)
|
||||
doc/order_module_design/
|
||||
|
||||
# Docker local build artifacts
|
||||
deploy/dist-ui/
|
||||
deploy/ruoyi-admin.jar
|
||||
|
||||
8
doc/zz_start_and_check.sh
Normal file
8
doc/zz_start_and_check.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
cd D:/DeXun_workspace/projects/erp-next
|
||||
mvn spring-boot:run -pl ruoyi-admin -q &
|
||||
PID=$!
|
||||
echo "App PID: $PID"
|
||||
sleep 40
|
||||
curl -s http://localhost:8080/v3/api-docs > D:/DeXun_workspace/projects/erp-next/doc/zz_api_result.json 2>&1
|
||||
echo "Done, check zz_api_result.json"
|
||||
797
doc/甲方客户界面及订单页面设计流程.md
Normal file
797
doc/甲方客户界面及订单页面设计流程.md
Normal file
@@ -0,0 +1,797 @@
|
||||
# 甲方客户界面及订单相关页面设计流程文档
|
||||
|
||||
## 一、Shipping_System Demo 全面分析
|
||||
|
||||
### 1.1 交互模式分析
|
||||
|
||||
#### 1.1.1 页面导航结构
|
||||
```
|
||||
顶部导航栏(固定)
|
||||
├── Logo区域(品牌标识)
|
||||
├── 主导航菜单(水平排列)
|
||||
│ ├── 总览(Dashboard)
|
||||
│ ├── 物料管理
|
||||
│ ├── 客户管理
|
||||
│ ├── 待发订单
|
||||
│ ├── 在途订单
|
||||
│ ├── 历史订单
|
||||
│ ├── 结单时间
|
||||
│ ├── 数据报表
|
||||
│ └── 操作记录
|
||||
└── 系统状态指示器
|
||||
|
||||
内容区域(单页应用模式)
|
||||
├── 页面标题区(Section Header)
|
||||
├── 工具栏(搜索/筛选/操作按钮)
|
||||
├── 数据表格/卡片区域
|
||||
└── 分页/统计信息
|
||||
```
|
||||
|
||||
#### 1.1.2 核心交互模式
|
||||
|
||||
| 交互类型 | 实现方式 | 用户体验特点 |
|
||||
|---------|---------|-------------|
|
||||
| 页面切换 | 单页应用(SPA),无刷新切换 | 快速、流畅 |
|
||||
| 数据加载 | 异步fetch API,loading状态 | 非阻塞、有反馈 |
|
||||
| 表单提交 | Modal弹窗,实时验证 | 沉浸式、不打断 |
|
||||
| 搜索筛选 | 防抖输入(300ms),即时响应 | 高效、省资源 |
|
||||
| 状态流转 | 按钮操作+状态标签变色 | 直观、可追踪 |
|
||||
| 数据展示 | 表格+卡片+图表混合 | 信息层次清晰 |
|
||||
|
||||
#### 1.1.3 关键交互细节
|
||||
|
||||
**订单状态流转:**
|
||||
```
|
||||
待发(PENDING) → 在途(TRANSIT) → 历史(HISTORY)
|
||||
↓ ↓
|
||||
编辑/删除 完成/撤回
|
||||
```
|
||||
|
||||
**预警提示机制:**
|
||||
- 交货期预警:红色边框+逾期天数标签
|
||||
- 状态标识:彩色Badge标签
|
||||
- 操作反馈:Toast消息提示
|
||||
|
||||
### 1.2 布局结构分析
|
||||
|
||||
#### 1.2.1 整体布局框架
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ [Logo] 总览 物料管理 客户管理 待发...在途...历史... │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 页面标题 [状态标签] │
|
||||
│ ───────────────────────────────────────────────────────── │
|
||||
│ │
|
||||
│ [搜索框] [筛选器] [新增按钮] │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ 数据表格 │ │
|
||||
│ │ ───────────────────────────────────────────────── │ │
|
||||
│ │ 订单号 客户 金额 交货期 状态 操作 │ │
|
||||
│ │ ORD-001 XXX ¥100 2026-06 PENDING [详][编][发] │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### 1.2.2 响应式断点设计
|
||||
|
||||
| 断点 | 宽度 | 布局调整 |
|
||||
|-----|------|---------|
|
||||
| Desktop | ≥1200px | 完整布局,多列展示 |
|
||||
| Tablet | 768-1199px | 简化表格,隐藏次要列 |
|
||||
| Mobile | <768px | 卡片式布局,垂直堆叠 |
|
||||
|
||||
#### 1.2.3 页面类型模板
|
||||
|
||||
**列表页模板:**
|
||||
- 顶部:标题 + 状态说明
|
||||
- 工具栏:搜索 + 筛选 + 主要操作
|
||||
- 内容区:数据表格
|
||||
- 底部:分页器
|
||||
|
||||
**详情/编辑页模板:**
|
||||
- Modal弹窗形式
|
||||
- 分区块表单(2列布局)
|
||||
- 底部操作按钮组
|
||||
|
||||
**报表页模板:**
|
||||
- KPI指标卡片行
|
||||
- 图表网格(2列)
|
||||
- 详细数据表格
|
||||
|
||||
### 1.3 功能模块划分
|
||||
|
||||
#### 1.3.1 模块结构图
|
||||
|
||||
```
|
||||
shipping_system
|
||||
├── 核心数据模块
|
||||
│ ├── 物料管理(SKU级)
|
||||
│ ├── 客户管理(企业/个人)
|
||||
│ └── 订单管理(生命周期)
|
||||
├── 业务流程模块
|
||||
│ ├── 订单状态流转
|
||||
│ ├── 结单时间管理
|
||||
│ └── 发货记录追踪
|
||||
├── 分析报表模块
|
||||
│ ├── 统计概览
|
||||
│ ├── 趋势分析
|
||||
│ └── 排名报表
|
||||
└── 系统管理模块
|
||||
├── 操作日志
|
||||
└── 数据审计
|
||||
```
|
||||
|
||||
#### 1.3.2 功能对照表
|
||||
|
||||
| 功能模块 | 当前项目对应 | 复用建议 |
|
||||
|---------|-------------|---------|
|
||||
| 客户管理 | 甲方客户管理 | 高度复用界面结构 |
|
||||
| 订单管理 | 销售订单/发货单 | 复用状态流转逻辑 |
|
||||
| 物料管理 | 产品/物料库 | 复用表格布局 |
|
||||
| 数据报表 | 统计分析 | 复用图表组件 |
|
||||
| 操作记录 | 系统日志 | 复用表格+筛选 |
|
||||
|
||||
---
|
||||
|
||||
## 二、视觉设计规范提取
|
||||
|
||||
### 2.1 色彩系统
|
||||
|
||||
#### 2.1.1 主色调(工业暗黑风)
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* 背景层级 */
|
||||
--bg: #1a1c1e; /* 主背景 - 深灰黑 */
|
||||
--bg2: #222426; /* 卡片背景 */
|
||||
--bg3: #2a2d30; /* 表头/输入框背景 */
|
||||
--bg4: #333639; /* 悬停背景 */
|
||||
|
||||
/* 边框层级 */
|
||||
--border: #3a3d41; /* 普通边框 */
|
||||
--border2: #4a4d52; /* 高亮边框 */
|
||||
|
||||
/* 文字层级 */
|
||||
--text: #c8ccd0; /* 主文字 - 浅灰 */
|
||||
--text2: #8a8f96; /* 次要文字 */
|
||||
--text3: #5a5f66; /* 禁用/提示文字 */
|
||||
|
||||
/* 强调色 */
|
||||
--yellow: #e8b400; /* 主强调色 - 琥珀金 */
|
||||
--yellow2: #ffcc00; /* 高亮 */
|
||||
|
||||
/* 状态色 */
|
||||
--red: #c0392b; /* 危险/逾期 */
|
||||
--red2: #e74c3c; /* 警告高亮 */
|
||||
--green: #27ae60; /* 成功/完成 */
|
||||
--green2: #2ecc71; /* 成功高亮 */
|
||||
--blue: #2980b9; /* 信息/在途 */
|
||||
--blue2: #3498db; /* 信息高亮 */
|
||||
--orange: #d35400; /* 警告/待发 */
|
||||
--orange2: #e67e22; /* 警告高亮 */
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.1.2 色彩应用场景
|
||||
|
||||
| 场景 | 颜色 | 用途 |
|
||||
|-----|------|------|
|
||||
| 品牌标识 | #e8b400 | Logo、主按钮、强调线 |
|
||||
| 成功状态 | #27ae60 | 完成、通过、正常 |
|
||||
| 警告状态 | #e67e22 | 待发、待处理 |
|
||||
| 危险状态 | #e74c3c | 逾期、删除、异常 |
|
||||
| 信息状态 | #3498db | 在途、进行中 |
|
||||
| 中性状态 | #8a8f96 | 草稿、默认 |
|
||||
|
||||
### 2.2 字体系统
|
||||
|
||||
```css
|
||||
:root {
|
||||
--font: 'JetBrains Mono', 'Consolas', 'Courier New', monospace;
|
||||
}
|
||||
```
|
||||
|
||||
| 元素 | 字号 | 字重 | 样式 |
|
||||
|-----|------|------|------|
|
||||
| Logo | 14px | 700 | 大写,字间距2px |
|
||||
| 导航 | 12px | 700 | 大写,字间距0.5px |
|
||||
| 页面标题 | 11px | 700 | 大写,字间距1.5px |
|
||||
| 表格表头 | 11px | 700 | 大写,字间距0.5px |
|
||||
| 表格内容 | 13px | 400 | 正常 |
|
||||
| 按钮 | 12px | 400 | 字间距0.5px |
|
||||
| 统计数字 | 28px | 700 | 字间距-1px |
|
||||
|
||||
### 2.3 间距系统
|
||||
|
||||
| 元素 | 间距值 |
|
||||
|-----|-------|
|
||||
| 页面内边距 | 20px |
|
||||
| 卡片内边距 | 16px 20px |
|
||||
| 表格单元格 | 8px 12px |
|
||||
| 按钮内边距 | 5px 14px |
|
||||
| 表单行间距 | 12px |
|
||||
| 组件间隙 | 12-16px |
|
||||
|
||||
### 2.4 组件样式
|
||||
|
||||
#### 2.4.1 按钮规范
|
||||
|
||||
```css
|
||||
/* 基础按钮 */
|
||||
button {
|
||||
padding: 5px 14px;
|
||||
font-size: 12px;
|
||||
border: 1px solid var(--border2);
|
||||
background: var(--bg3);
|
||||
transition: all .15s;
|
||||
}
|
||||
|
||||
/* 主要按钮 */
|
||||
.btn-primary {
|
||||
background: var(--yellow);
|
||||
color: #000;
|
||||
border-color: var(--yellow);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* 危险按钮 */
|
||||
.btn-danger {
|
||||
border-color: var(--red);
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
/* 成功按钮 */
|
||||
.btn-success {
|
||||
border-color: var(--green);
|
||||
color: var(--green);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4.2 表格规范
|
||||
|
||||
```css
|
||||
th {
|
||||
background: var(--bg3);
|
||||
color: var(--text2);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
border-bottom: 2px solid var(--yellow);
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
tr:hover td {
|
||||
background: var(--bg3);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.4.3 状态标签(Badge)
|
||||
|
||||
```css
|
||||
.badge-pending { /* 待发 */
|
||||
color: #e67e22;
|
||||
border-color: #e67e22;
|
||||
background: rgba(230,126,34,.1);
|
||||
}
|
||||
|
||||
.badge-transit { /* 在途 */
|
||||
color: #3498db;
|
||||
border-color: #3498db;
|
||||
background: rgba(52,152,219,.1);
|
||||
}
|
||||
|
||||
.badge-history { /* 历史 */
|
||||
color: #27ae60;
|
||||
border-color: #27ae60;
|
||||
background: rgba(39,174,96,.1);
|
||||
}
|
||||
|
||||
.badge-warn { /* 警告/逾期 */
|
||||
color: var(--red2);
|
||||
border-color: var(--red2);
|
||||
background: rgba(231,76,60,.1);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、设计流程规划
|
||||
|
||||
### 3.1 阶段一:需求分析与确认(3-5天)
|
||||
|
||||
#### 3.1.1 工作内容
|
||||
|
||||
1. **业务需求梳理**
|
||||
- 甲方客户管理流程梳理
|
||||
- 订单生命周期定义
|
||||
- 状态流转规则确认
|
||||
- 权限角色划分
|
||||
|
||||
2. **现有系统分析**
|
||||
- 当前项目架构调研
|
||||
- 数据模型分析
|
||||
- API接口梳理
|
||||
- 复用组件盘点
|
||||
|
||||
3. **竞品/参考分析**
|
||||
- shipping_system demo深度体验
|
||||
- 行业最佳实践研究
|
||||
- 用户痛点收集
|
||||
|
||||
#### 3.1.2 交付物
|
||||
|
||||
| 交付物 | 标准 | 负责人 |
|
||||
|-------|------|-------|
|
||||
| 需求规格说明书 | 功能点清单、业务流程图 | 产品经理 |
|
||||
| 数据模型设计 | ER图、字段定义 | 后端开发 |
|
||||
| 接口文档初稿 | API列表、字段定义 | 后端开发 |
|
||||
| 竞品分析报告 | 优缺点对比、借鉴点 | 设计师 |
|
||||
|
||||
#### 3.1.3 质量验收标准
|
||||
|
||||
- [ ] 所有功能点已明确优先级(P0/P1/P2)
|
||||
- [ ] 业务流程图通过评审
|
||||
- [ ] 数据模型覆盖所有业务场景
|
||||
- [ ] 技术可行性已确认
|
||||
|
||||
---
|
||||
|
||||
### 3.2 阶段二:信息架构设计(2-3天)
|
||||
|
||||
#### 3.2.1 工作内容
|
||||
|
||||
1. **站点地图设计**
|
||||
```
|
||||
甲方客户管理
|
||||
├── 客户列表
|
||||
│ ├── 搜索/筛选
|
||||
│ ├── 新增客户
|
||||
│ ├── 编辑客户
|
||||
│ └── 查看详情
|
||||
├── 客户详情
|
||||
│ ├── 基本信息
|
||||
│ ├── 历史订单
|
||||
│ └── 联系记录
|
||||
└── 客户统计
|
||||
|
||||
订单管理
|
||||
├── 待发订单
|
||||
├── 在途订单
|
||||
├── 历史订单
|
||||
└── 订单详情
|
||||
├── 基本信息
|
||||
├── 物料明细
|
||||
├── 状态流转
|
||||
└── 操作日志
|
||||
```
|
||||
|
||||
2. **导航结构设计**
|
||||
- 主导航菜单规划
|
||||
- 面包屑导航规则
|
||||
- 快捷入口设计
|
||||
|
||||
3. **页面层级规划**
|
||||
- 一级页面:列表页
|
||||
- 二级页面:详情页/编辑页
|
||||
- 三级页面:关联信息
|
||||
|
||||
#### 3.2.2 交付物
|
||||
|
||||
| 交付物 | 标准 | 工具 |
|
||||
|-------|------|------|
|
||||
| 站点地图 | 完整页面层级 | XMind/ProcessOn |
|
||||
| 用户流程图 | 关键任务流程 | Figma/Draw.io |
|
||||
| 信息架构图 | 模块关系图 | 架构图工具 |
|
||||
|
||||
#### 3.2.3 质量验收标准
|
||||
|
||||
- [ ] 所有页面层级不超过3级
|
||||
- [ ] 核心任务完成路径≤3步
|
||||
- [ ] 导航结构符合用户心智模型
|
||||
- [ ] 与现有系统导航风格一致
|
||||
|
||||
---
|
||||
|
||||
### 3.3 阶段三:线框图绘制(3-5天)
|
||||
|
||||
#### 3.3.1 工作内容
|
||||
|
||||
1. **页面布局线框**
|
||||
- 列表页布局(参考shipping_system)
|
||||
- 详情页布局
|
||||
- 表单页布局
|
||||
- Modal弹窗布局
|
||||
|
||||
2. **组件布局规划**
|
||||
- 表格列宽分配
|
||||
- 表单字段排列
|
||||
- 按钮位置规划
|
||||
- 响应式断点设计
|
||||
|
||||
3. **交互流程标注**
|
||||
- 点击热区标注
|
||||
- 状态变化说明
|
||||
- 转场动画示意
|
||||
|
||||
#### 3.3.2 页面线框清单
|
||||
|
||||
| 页面 | 优先级 | 复杂度 |
|
||||
|-----|-------|-------|
|
||||
| 甲方客户列表页 | P0 | 中 |
|
||||
| 甲方客户详情页 | P0 | 中 |
|
||||
| 客户编辑/新增页 | P0 | 低 |
|
||||
| 待发订单列表页 | P0 | 中 |
|
||||
| 在途订单列表页 | P0 | 中 |
|
||||
| 历史订单列表页 | P0 | 中 |
|
||||
| 订单详情页 | P0 | 高 |
|
||||
| 订单编辑/新增页 | P0 | 高 |
|
||||
| 订单统计报表 | P1 | 中 |
|
||||
| 客户统计报表 | P1 | 中 |
|
||||
|
||||
#### 3.3.3 交付物
|
||||
|
||||
| 交付物 | 标准 | 工具 |
|
||||
|-------|------|------|
|
||||
| 低保真线框图 | 灰度,无色彩 | Figma/Axure |
|
||||
| 交互说明文档 | 标注交互细节 | 文档工具 |
|
||||
| 页面流程图 | 页面跳转关系 | 流程图工具 |
|
||||
|
||||
#### 3.3.4 质量验收标准
|
||||
|
||||
- [ ] 所有P0页面线框已完成
|
||||
- [ ] 布局符合shipping_system风格
|
||||
- [ ] 核心交互路径已标注
|
||||
- [ ] 开发团队已评审通过
|
||||
|
||||
---
|
||||
|
||||
### 3.4 阶段四:视觉设计规范制定(2-3天)
|
||||
|
||||
#### 3.4.1 工作内容
|
||||
|
||||
1. **色彩系统定义**
|
||||
- 提取shipping_system配色
|
||||
- 适配当前项目品牌色
|
||||
- 定义状态色规范
|
||||
- 输出CSS变量
|
||||
|
||||
2. **字体系统定义**
|
||||
- 中文字体选择(建议:思源黑体/微软雅黑)
|
||||
- 字号层级定义
|
||||
- 行高/字间距规范
|
||||
|
||||
3. **组件视觉规范**
|
||||
- 按钮样式(主/次/危险/成功)
|
||||
- 输入框样式
|
||||
- 表格样式
|
||||
- 卡片/面板样式
|
||||
- 标签/Badge样式
|
||||
- Modal弹窗样式
|
||||
|
||||
4. **图标系统**
|
||||
- 图标风格统一(线性/面性)
|
||||
- 图标尺寸规范
|
||||
- 常用图标清单
|
||||
|
||||
#### 3.4.2 设计规范输出
|
||||
|
||||
```
|
||||
design-system/
|
||||
├── colors/
|
||||
│ ├── palette.scss # 色板定义
|
||||
│ ├── semantic.scss # 语义化颜色
|
||||
│ └── dark-theme.scss # 暗黑主题
|
||||
├── typography/
|
||||
│ ├── fonts.scss # 字体定义
|
||||
│ ├── scale.scss # 字号层级
|
||||
│ └── styles.scss # 文字样式
|
||||
├── components/
|
||||
│ ├── buttons.scss # 按钮规范
|
||||
│ ├── forms.scss # 表单规范
|
||||
│ ├── tables.scss # 表格规范
|
||||
│ ├── cards.scss # 卡片规范
|
||||
│ └── modals.scss # 弹窗规范
|
||||
└── spacing/
|
||||
├── grid.scss # 栅格系统
|
||||
└── spacing.scss # 间距系统
|
||||
```
|
||||
|
||||
#### 3.4.3 交付物
|
||||
|
||||
| 交付物 | 标准 | 工具 |
|
||||
|-------|------|------|
|
||||
| 视觉设计规范文档 | 完整Design Token | Figma/文档 |
|
||||
| 组件样式库 | SCSS/CSS代码 | 代码仓库 |
|
||||
| 图标资源包 | SVG格式 | 设计工具 |
|
||||
|
||||
#### 3.4.4 质量验收标准
|
||||
|
||||
- [ ] 色彩对比度符合WCAG 2.1 AA标准
|
||||
- [ ] 所有组件有对应的代码实现
|
||||
- [ ] 与shipping_system视觉风格一致
|
||||
- [ ] 开发团队可无障碍使用
|
||||
|
||||
---
|
||||
|
||||
### 3.5 阶段五:高保真原型制作(5-7天)
|
||||
|
||||
#### 3.5.1 工作内容
|
||||
|
||||
1. **高保真页面设计**
|
||||
- 基于线框图添加视觉细节
|
||||
- 应用设计规范
|
||||
- 填充真实数据示例
|
||||
|
||||
2. **交互原型制作**
|
||||
- 页面跳转链接
|
||||
- 交互动效定义
|
||||
- 状态变化演示
|
||||
|
||||
3. **响应式设计**
|
||||
- Desktop端(≥1200px)
|
||||
- Tablet端(768-1199px)
|
||||
- Mobile端(<768px)
|
||||
|
||||
#### 3.5.2 关键页面设计要点
|
||||
|
||||
**甲方客户列表页:**
|
||||
- 顶部:标题 + 客户统计
|
||||
- 工具栏:搜索框 + 客户类型筛选 + 新增按钮
|
||||
- 表格:编号/名称/联系人/电话/城市/订单数/状态/操作
|
||||
- 操作列:详情/编辑/删除
|
||||
|
||||
**订单详情页:**
|
||||
- 左侧:订单基本信息卡片
|
||||
- 右侧:状态流转时间线
|
||||
- 下方:物料明细表格
|
||||
- 底部:操作按钮组(发货/完成/撤回)
|
||||
|
||||
**订单编辑页:**
|
||||
- 分步表单或标签页
|
||||
- 基本信息区
|
||||
- 物料明细区(可增删改)
|
||||
- 实时金额计算
|
||||
|
||||
#### 3.5.3 交付物
|
||||
|
||||
| 交付物 | 标准 | 工具 |
|
||||
|-------|------|------|
|
||||
| 高保真设计稿 | 所有P0页面 | Figma |
|
||||
| 交互原型 | 可点击演示 | Figma/Axure |
|
||||
| 设计标注 | 尺寸/颜色/字体 | Figma Dev Mode |
|
||||
| 切图资源 | 1x/2x/3x | Figma Export |
|
||||
|
||||
#### 3.5.4 质量验收标准
|
||||
|
||||
- [ ] 所有P0页面高保真设计完成
|
||||
- [ ] 交互原型可完整演示核心流程
|
||||
- [ ] 视觉还原度与shipping_system≥90%
|
||||
- [ ] 设计稿已通过产品/开发评审
|
||||
|
||||
---
|
||||
|
||||
### 3.6 阶段六:交互细节设计(2-3天)
|
||||
|
||||
#### 3.6.1 工作内容
|
||||
|
||||
1. **微交互设计**
|
||||
- 按钮悬停效果(边框变色+文字变色)
|
||||
- 表格行悬停效果(背景色变化)
|
||||
- 加载状态设计
|
||||
- 空状态设计
|
||||
|
||||
2. **动效规范**
|
||||
- 页面切换过渡(建议:淡入淡出 200ms)
|
||||
- Modal弹窗动画(建议:缩放+淡入 150ms)
|
||||
- 数据刷新动画
|
||||
- 状态变化动画
|
||||
|
||||
3. **反馈机制**
|
||||
- 成功提示(绿色Toast)
|
||||
- 错误提示(红色Toast)
|
||||
- 警告提示(橙色Alert)
|
||||
- 加载提示(Loading Spinner)
|
||||
|
||||
4. **键盘快捷键**
|
||||
- Ctrl+S 保存
|
||||
- ESC 关闭弹窗
|
||||
- Enter 确认
|
||||
- / 聚焦搜索框
|
||||
|
||||
#### 3.6.2 交互规范文档
|
||||
|
||||
```
|
||||
interactions/
|
||||
├── hover-states.md # 悬停状态规范
|
||||
├── transitions.md # 转场动画规范
|
||||
├── feedback.md # 反馈机制规范
|
||||
├── keyboard-shortcuts.md # 快捷键规范
|
||||
└── accessibility.md # 无障碍规范
|
||||
```
|
||||
|
||||
#### 3.6.3 交付物
|
||||
|
||||
| 交付物 | 标准 | 工具 |
|
||||
|-------|------|------|
|
||||
| 交互规范文档 | 详细交互说明 | 文档工具 |
|
||||
| 动效参数表 | 时长/缓动函数 | 表格 |
|
||||
| 交互Demo | 关键交互演示 | Figma/视频 |
|
||||
|
||||
#### 3.6.4 质量验收标准
|
||||
|
||||
- [ ] 所有交互有明确的触发条件和反馈
|
||||
- [ ] 动效时长符合人体工程学(150-300ms)
|
||||
- [ ] 无障碍访问支持(键盘/屏幕阅读器)
|
||||
- [ ] 性能影响已评估(避免重绘/重排)
|
||||
|
||||
---
|
||||
|
||||
### 3.7 阶段七:用户测试与反馈优化(3-5天)
|
||||
|
||||
#### 3.7.1 工作内容
|
||||
|
||||
1. **可用性测试**
|
||||
- 测试对象:目标用户5-8人
|
||||
- 测试任务:
|
||||
- 创建新客户
|
||||
- 创建新订单
|
||||
- 查询客户历史订单
|
||||
- 变更订单状态
|
||||
- 测试指标:
|
||||
- 任务完成率
|
||||
- 完成时间
|
||||
- 错误率
|
||||
- 满意度评分
|
||||
|
||||
2. **A/B测试(可选)**
|
||||
- 表格视图 vs 卡片视图
|
||||
- 不同按钮位置
|
||||
- 不同颜色方案
|
||||
|
||||
3. **反馈收集与优化**
|
||||
- 整理测试问题
|
||||
- 优先级排序
|
||||
- 设计调整
|
||||
- 二次验证
|
||||
|
||||
#### 3.7.2 测试检查清单
|
||||
|
||||
| 检查项 | 测试方法 | 通过标准 |
|
||||
|-------|---------|---------|
|
||||
| 核心任务完成率 | 用户测试 | ≥90% |
|
||||
| 首次使用无帮助完成 | 用户测试 | ≥70% |
|
||||
| 页面加载时间 | 性能测试 | ≤2s |
|
||||
| 交互响应时间 | 性能测试 | ≤100ms |
|
||||
| 视觉一致性 | 设计走查 | 无偏差 |
|
||||
| 代码实现一致性 | 开发走查 | 还原度≥95% |
|
||||
|
||||
#### 3.7.3 交付物
|
||||
|
||||
| 交付物 | 标准 | 工具 |
|
||||
|-------|------|------|
|
||||
| 测试报告 | 问题清单+改进建议 | 文档工具 |
|
||||
| 优化后的设计稿 | 修改后的高保真 | Figma |
|
||||
| 设计走查记录 | 开发还原度检查 | 表格 |
|
||||
|
||||
#### 3.7.4 质量验收标准
|
||||
|
||||
- [ ] 核心任务完成率≥90%
|
||||
- [ ] 严重问题已修复
|
||||
- [ ] 开发还原度≥95%
|
||||
- [ ] 产品/业务方验收通过
|
||||
|
||||
---
|
||||
|
||||
## 四、实施建议
|
||||
|
||||
### 4.1 技术实现建议
|
||||
|
||||
#### 4.1.1 前端技术栈
|
||||
|
||||
| 技术 | 用途 | 说明 |
|
||||
|-----|------|------|
|
||||
| Vue 2 | 框架 | 与现有项目保持一致 |
|
||||
| Element UI | 组件库 | 基于shipping_system风格定制主题 |
|
||||
| SCSS | 样式 | 使用CSS变量实现主题 |
|
||||
| ECharts | 图表 | 统一图表风格 |
|
||||
|
||||
#### 4.1.2 样式实现策略
|
||||
|
||||
```scss
|
||||
// 主题变量文件:styles/theme.scss
|
||||
:root {
|
||||
// 提取shipping_system配色
|
||||
--smg-bg: #1a1c1e;
|
||||
--smg-bg-card: #222426;
|
||||
--smg-bg-input: #2a2d30;
|
||||
--smg-border: #3a3d41;
|
||||
--smg-text: #c8ccd0;
|
||||
--smg-text-secondary: #8a8f96;
|
||||
--smg-primary: #e8b400;
|
||||
--smg-success: #27ae60;
|
||||
--smg-warning: #e67e22;
|
||||
--smg-danger: #e74c3c;
|
||||
--smg-info: #3498db;
|
||||
}
|
||||
|
||||
// Element UI主题覆盖
|
||||
.el-button--primary {
|
||||
background-color: var(--smg-primary);
|
||||
border-color: var(--smg-primary);
|
||||
color: #000;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
background-color: var(--smg-bg-card);
|
||||
th {
|
||||
background-color: var(--smg-bg-input);
|
||||
border-bottom: 2px solid var(--smg-primary);
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 组件复用建议
|
||||
|
||||
| shipping_system组件 | 当前项目对应 | 复用方式 |
|
||||
|-------------------|-------------|---------|
|
||||
| 顶部导航栏 | 现有侧边栏+顶部 | 提取配色方案 |
|
||||
| 数据表格 | Element Table | 定制主题样式 |
|
||||
| Modal弹窗 | Element Dialog | 定制暗黑主题 |
|
||||
| 状态Badge | Element Tag | 定制颜色方案 |
|
||||
| 统计卡片 | 自定义组件 | 复用布局结构 |
|
||||
| 搜索框 | Element Input | 添加搜索图标 |
|
||||
| 表单布局 | Element Form | 复用2列布局 |
|
||||
|
||||
### 4.3 开发排期建议
|
||||
|
||||
| 阶段 | 工期 | 并行任务 |
|
||||
|-----|------|---------|
|
||||
| 需求分析 | 3-5天 | 技术预研 |
|
||||
| 信息架构 | 2-3天 | - |
|
||||
| 线框图 | 3-5天 | 接口开发 |
|
||||
| 视觉规范 | 2-3天 | 组件开发 |
|
||||
| 高保真原型 | 5-7天 | 后端开发 |
|
||||
| 交互细节 | 2-3天 | 前端开发 |
|
||||
| 测试优化 | 3-5天 | 联调测试 |
|
||||
|
||||
**总计:20-30天**
|
||||
|
||||
---
|
||||
|
||||
## 五、附录
|
||||
|
||||
### 5.1 参考资源
|
||||
|
||||
- shipping_system demo路径:`/shipping_system/static/index.html`
|
||||
- 当前项目前端路径:`/ruoyi-ui/src/views/bid/`
|
||||
- 设计规范文档:`/doc/design-system/`
|
||||
|
||||
### 5.2 术语表
|
||||
|
||||
| 术语 | 说明 |
|
||||
|-----|------|
|
||||
| SMG | Shipping Management System 发货管理系统 |
|
||||
| RFQ | Request for Quotation 询价单 |
|
||||
| SKU | Stock Keeping Unit 库存单位 |
|
||||
| P0/P1/P2 | 优先级:高/中/低 |
|
||||
|
||||
### 5.3 版本记录
|
||||
|
||||
| 版本 | 日期 | 修改内容 | 作者 |
|
||||
|-----|------|---------|------|
|
||||
| v1.0 | 2026-06-03 | 初始版本 | AI Assistant |
|
||||
|
||||
---
|
||||
|
||||
**文档结束**
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.ruoyi.web.controller.bid;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.system.domain.bid.BizClient;
|
||||
import com.ruoyi.system.service.bid.IBizClientService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/bid/client")
|
||||
public class BizClientController extends BaseController {
|
||||
@Autowired
|
||||
private IBizClientService service;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:client:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(BizClient query) {
|
||||
startPage();
|
||||
List<BizClient> list = service.selectBizClientList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:client:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
return success(service.selectBizClientById(id));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:client:add')")
|
||||
@Log(title = "甲方客户", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody BizClient record) {
|
||||
record.setCreateBy(getUsername());
|
||||
return toAjax(service.insertBizClient(record));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:client:edit')")
|
||||
@Log(title = "甲方客户", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody BizClient record) {
|
||||
record.setUpdateBy(getUsername());
|
||||
return toAjax(service.updateBizClient(record));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:client:remove')")
|
||||
@Log(title = "甲方客户", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{clientIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] clientIds) {
|
||||
return toAjax(service.deleteBizClientByIds(clientIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询客户的关联历史发货单
|
||||
* 链路: client → client_quote → rfq → delivery_order
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('bid:client:query')")
|
||||
@GetMapping("/{clientId}/orders")
|
||||
public AjaxResult clientOrders(@PathVariable Long clientId) {
|
||||
return success(service.selectClientDeliveryOrders(clientId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.ruoyi.web.controller.bid;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
|
||||
import com.ruoyi.system.service.bid.IBizDeliveryOrderService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/bid/delivery")
|
||||
public class BizDeliveryOrderController extends BaseController {
|
||||
@Autowired
|
||||
private IBizDeliveryOrderService service;
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:order:pending') or @ss.hasPermi('bid:order:transit') or @ss.hasPermi('bid:order:history')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(BizDeliveryOrder query) {
|
||||
startPage();
|
||||
List<BizDeliveryOrder> list = service.selectBizDeliveryOrderList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:order:query')")
|
||||
@GetMapping("/{id}")
|
||||
public AjaxResult getInfo(@PathVariable Long id) {
|
||||
return success(service.selectBizDeliveryOrderById(id));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:order:status')")
|
||||
@Log(title = "发货管理", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody BizDeliveryOrder record) {
|
||||
record.setCreateBy(getUsername());
|
||||
return toAjax(service.insertBizDeliveryOrder(record));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:order:status')")
|
||||
@Log(title = "发货管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody BizDeliveryOrder record) {
|
||||
record.setUpdateBy(getUsername());
|
||||
return toAjax(service.updateBizDeliveryOrder(record));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('bid:order:pending')")
|
||||
@Log(title = "发货管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{doIds}")
|
||||
public AjaxResult remove(@PathVariable Long[] doIds) {
|
||||
return toAjax(service.deleteBizDeliveryOrderByIds(doIds));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.ruoyi.system.domain.bid;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
|
||||
public class BizClient extends BaseEntity {
|
||||
private Long clientId;
|
||||
private Long tenantId;
|
||||
private String clientNo;
|
||||
private String clientName;
|
||||
private String contact;
|
||||
private String phone;
|
||||
private String email;
|
||||
private String city;
|
||||
private String address;
|
||||
private String grade;
|
||||
private String source;
|
||||
private String status;
|
||||
|
||||
public Long getClientId() { return clientId; }
|
||||
public void setClientId(Long clientId) { this.clientId = clientId; }
|
||||
public Long getTenantId() { return tenantId; }
|
||||
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
|
||||
public String getClientNo() { return clientNo; }
|
||||
public void setClientNo(String clientNo) { this.clientNo = clientNo; }
|
||||
public String getClientName() { return clientName; }
|
||||
public void setClientName(String clientName) { this.clientName = clientName; }
|
||||
public String getContact() { return contact; }
|
||||
public void setContact(String contact) { this.contact = contact; }
|
||||
public String getPhone() { return phone; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
public String getCity() { return city; }
|
||||
public void setCity(String city) { this.city = city; }
|
||||
public String getAddress() { return address; }
|
||||
public void setAddress(String address) { this.address = address; }
|
||||
public String getGrade() { return grade; }
|
||||
public void setGrade(String grade) { this.grade = grade; }
|
||||
public String getSource() { return source; }
|
||||
public void setSource(String source) { this.source = source; }
|
||||
public String getStatus() { return status; }
|
||||
public void setStatus(String status) { this.status = status; }
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.ruoyi.system.domain.bid;
|
||||
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class BizDeliveryOrder extends BaseEntity {
|
||||
private Long doId;
|
||||
private Long tenantId;
|
||||
private String doNo;
|
||||
private Long rfqId;
|
||||
private Long quotationId;
|
||||
private Long supplierId;
|
||||
private BigDecimal totalAmount;
|
||||
private String currency;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date deliveryDate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date delayDate;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date actualCloseDate;
|
||||
private String closeDateSetBy;
|
||||
private String deliveryStatus;
|
||||
private List<BizDeliveryOrderItem> items;
|
||||
private String supplierName;
|
||||
|
||||
public Long getDoId() { return doId; }
|
||||
public void setDoId(Long doId) { this.doId = doId; }
|
||||
public Long getTenantId() { return tenantId; }
|
||||
public void setTenantId(Long tenantId) { this.tenantId = tenantId; }
|
||||
public String getDoNo() { return doNo; }
|
||||
public void setDoNo(String doNo) { this.doNo = doNo; }
|
||||
public Long getRfqId() { return rfqId; }
|
||||
public void setRfqId(Long rfqId) { this.rfqId = rfqId; }
|
||||
public Long getQuotationId() { return quotationId; }
|
||||
public void setQuotationId(Long quotationId) { this.quotationId = quotationId; }
|
||||
public Long getSupplierId() { return supplierId; }
|
||||
public void setSupplierId(Long supplierId) { this.supplierId = supplierId; }
|
||||
public BigDecimal getTotalAmount() { return totalAmount; }
|
||||
public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }
|
||||
public String getCurrency() { return currency; }
|
||||
public void setCurrency(String currency) { this.currency = currency; }
|
||||
public Date getDeliveryDate() { return deliveryDate; }
|
||||
public void setDeliveryDate(Date deliveryDate) { this.deliveryDate = deliveryDate; }
|
||||
public Date getDelayDate() { return delayDate; }
|
||||
public void setDelayDate(Date delayDate) { this.delayDate = delayDate; }
|
||||
public Date getActualCloseDate() { return actualCloseDate; }
|
||||
public void setActualCloseDate(Date actualCloseDate) { this.actualCloseDate = actualCloseDate; }
|
||||
public String getCloseDateSetBy() { return closeDateSetBy; }
|
||||
public void setCloseDateSetBy(String closeDateSetBy) { this.closeDateSetBy = closeDateSetBy; }
|
||||
public String getDeliveryStatus() { return deliveryStatus; }
|
||||
public void setDeliveryStatus(String deliveryStatus) { this.deliveryStatus = deliveryStatus; }
|
||||
public List<BizDeliveryOrderItem> getItems() { return items; }
|
||||
public void setItems(List<BizDeliveryOrderItem> items) { this.items = items; }
|
||||
public String getSupplierName() { return supplierName; }
|
||||
public void setSupplierName(String supplierName) { this.supplierName = supplierName; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.ruoyi.system.domain.bid;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class BizDeliveryOrderItem {
|
||||
private Long itemId;
|
||||
private Long doId;
|
||||
private Long materialId;
|
||||
private String materialName;
|
||||
private String spec;
|
||||
private String unit;
|
||||
private BigDecimal quantity;
|
||||
private BigDecimal unitPrice;
|
||||
private BigDecimal totalPrice;
|
||||
private String remark;
|
||||
|
||||
public Long getItemId() { return itemId; }
|
||||
public void setItemId(Long itemId) { this.itemId = itemId; }
|
||||
public Long getDoId() { return doId; }
|
||||
public void setDoId(Long doId) { this.doId = doId; }
|
||||
public Long getMaterialId() { return materialId; }
|
||||
public void setMaterialId(Long materialId) { this.materialId = materialId; }
|
||||
public String getMaterialName() { return materialName; }
|
||||
public void setMaterialName(String materialName) { this.materialName = materialName; }
|
||||
public String getSpec() { return spec; }
|
||||
public void setSpec(String spec) { this.spec = spec; }
|
||||
public String getUnit() { return unit; }
|
||||
public void setUnit(String unit) { this.unit = unit; }
|
||||
public BigDecimal getQuantity() { return quantity; }
|
||||
public void setQuantity(BigDecimal quantity) { this.quantity = quantity; }
|
||||
public BigDecimal getUnitPrice() { return unitPrice; }
|
||||
public void setUnitPrice(BigDecimal unitPrice) { this.unitPrice = unitPrice; }
|
||||
public BigDecimal getTotalPrice() { return totalPrice; }
|
||||
public void setTotalPrice(BigDecimal totalPrice) { this.totalPrice = totalPrice; }
|
||||
public String getRemark() { return remark; }
|
||||
public void setRemark(String remark) { this.remark = remark; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.system.mapper.bid;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizClient;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface BizClientMapper {
|
||||
List<BizClient> selectBizClientList(BizClient query);
|
||||
BizClient selectBizClientById(Long id);
|
||||
int insertBizClient(BizClient record);
|
||||
int updateBizClient(BizClient record);
|
||||
int deleteBizClientById(Long id);
|
||||
int deleteBizClientByIds(Long[] ids);
|
||||
List<Map<String, Object>> selectClientDeliveryOrders(Long clientId);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ruoyi.system.mapper.bid;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizDeliveryOrderItem;
|
||||
import java.util.List;
|
||||
|
||||
public interface BizDeliveryOrderItemMapper {
|
||||
List<BizDeliveryOrderItem> selectItemsByDoId(Long doId);
|
||||
int insertBizDeliveryOrderItem(BizDeliveryOrderItem item);
|
||||
int deleteByDoId(Long doId);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ruoyi.system.mapper.bid;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
|
||||
import java.util.List;
|
||||
|
||||
public interface BizDeliveryOrderMapper {
|
||||
List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query);
|
||||
BizDeliveryOrder selectBizDeliveryOrderById(Long id);
|
||||
int insertBizDeliveryOrder(BizDeliveryOrder record);
|
||||
int updateBizDeliveryOrder(BizDeliveryOrder record);
|
||||
int deleteBizDeliveryOrderById(Long id);
|
||||
int deleteBizDeliveryOrderByIds(Long[] ids);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.system.service.bid;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizClient;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IBizClientService {
|
||||
List<BizClient> selectBizClientList(BizClient query);
|
||||
BizClient selectBizClientById(Long id);
|
||||
int insertBizClient(BizClient record);
|
||||
int updateBizClient(BizClient record);
|
||||
int deleteBizClientById(Long id);
|
||||
int deleteBizClientByIds(Long[] ids);
|
||||
List<Map<String, Object>> selectClientDeliveryOrders(Long clientId);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.ruoyi.system.service.bid;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
|
||||
import java.util.List;
|
||||
|
||||
public interface IBizDeliveryOrderService {
|
||||
List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query);
|
||||
BizDeliveryOrder selectBizDeliveryOrderById(Long id);
|
||||
int insertBizDeliveryOrder(BizDeliveryOrder record);
|
||||
int updateBizDeliveryOrder(BizDeliveryOrder record);
|
||||
int deleteBizDeliveryOrderById(Long id);
|
||||
int deleteBizDeliveryOrderByIds(Long[] ids);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ruoyi.system.service.bid.impl;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizClient;
|
||||
import com.ruoyi.system.mapper.bid.BizClientMapper;
|
||||
import com.ruoyi.system.service.bid.IBizClientService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class BizClientServiceImpl implements IBizClientService {
|
||||
@Autowired
|
||||
private BizClientMapper mapper;
|
||||
|
||||
@Override
|
||||
public List<BizClient> selectBizClientList(BizClient query) {
|
||||
return mapper.selectBizClientList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BizClient selectBizClientById(Long id) {
|
||||
return mapper.selectBizClientById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertBizClient(BizClient record) {
|
||||
return mapper.insertBizClient(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateBizClient(BizClient record) {
|
||||
return mapper.updateBizClient(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteBizClientById(Long id) {
|
||||
return mapper.deleteBizClientById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteBizClientByIds(Long[] ids) {
|
||||
return mapper.deleteBizClientByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> selectClientDeliveryOrders(Long clientId) {
|
||||
return mapper.selectClientDeliveryOrders(clientId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.ruoyi.system.service.bid.impl;
|
||||
|
||||
import com.ruoyi.system.domain.bid.BizDeliveryOrder;
|
||||
import com.ruoyi.system.domain.bid.BizDeliveryOrderItem;
|
||||
import com.ruoyi.system.mapper.bid.BizDeliveryOrderMapper;
|
||||
import com.ruoyi.system.mapper.bid.BizDeliveryOrderItemMapper;
|
||||
import com.ruoyi.system.service.bid.IBizDeliveryOrderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class BizDeliveryOrderServiceImpl implements IBizDeliveryOrderService {
|
||||
@Autowired
|
||||
private BizDeliveryOrderMapper mapper;
|
||||
@Autowired
|
||||
private BizDeliveryOrderItemMapper itemMapper;
|
||||
|
||||
@Override
|
||||
public List<BizDeliveryOrder> selectBizDeliveryOrderList(BizDeliveryOrder query) {
|
||||
return mapper.selectBizDeliveryOrderList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BizDeliveryOrder selectBizDeliveryOrderById(Long id) {
|
||||
BizDeliveryOrder d = mapper.selectBizDeliveryOrderById(id);
|
||||
if (d != null) d.setItems(itemMapper.selectItemsByDoId(id));
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertBizDeliveryOrder(BizDeliveryOrder record) {
|
||||
if (record.getDoNo() == null || record.getDoNo().isEmpty()) {
|
||||
record.setDoNo("DO" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
|
||||
}
|
||||
if (record.getDeliveryStatus() == null || record.getDeliveryStatus().isEmpty()) {
|
||||
record.setDeliveryStatus("pending");
|
||||
}
|
||||
int rows = mapper.insertBizDeliveryOrder(record);
|
||||
if (record.getItems() != null) {
|
||||
BigDecimal total = BigDecimal.ZERO;
|
||||
for (BizDeliveryOrderItem item : record.getItems()) {
|
||||
item.setDoId(record.getDoId());
|
||||
if (item.getUnitPrice() != null && item.getQuantity() != null) {
|
||||
item.setTotalPrice(item.getUnitPrice().multiply(item.getQuantity()));
|
||||
total = total.add(item.getTotalPrice());
|
||||
}
|
||||
itemMapper.insertBizDeliveryOrderItem(item);
|
||||
}
|
||||
record.setTotalAmount(total);
|
||||
mapper.updateBizDeliveryOrder(record);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateBizDeliveryOrder(BizDeliveryOrder record) {
|
||||
itemMapper.deleteByDoId(record.getDoId());
|
||||
if (record.getItems() != null) {
|
||||
BigDecimal total = BigDecimal.ZERO;
|
||||
for (BizDeliveryOrderItem item : record.getItems()) {
|
||||
item.setDoId(record.getDoId());
|
||||
if (item.getUnitPrice() != null && item.getQuantity() != null) {
|
||||
item.setTotalPrice(item.getUnitPrice().multiply(item.getQuantity()));
|
||||
total = total.add(item.getTotalPrice());
|
||||
}
|
||||
itemMapper.insertBizDeliveryOrderItem(item);
|
||||
}
|
||||
record.setTotalAmount(total);
|
||||
}
|
||||
return mapper.updateBizDeliveryOrder(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteBizDeliveryOrderById(Long id) {
|
||||
return mapper.deleteBizDeliveryOrderById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteBizDeliveryOrderByIds(Long[] ids) {
|
||||
return mapper.deleteBizDeliveryOrderByIds(ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.bid.BizClientMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.ruoyi.system.domain.bid.BizClient">
|
||||
<id property="clientId" column="client_id"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="clientNo" column="client_no"/>
|
||||
<result property="clientName" column="client_name"/>
|
||||
<result property="contact" column="contact"/>
|
||||
<result property="phone" column="phone"/>
|
||||
<result property="email" column="email"/>
|
||||
<result property="city" column="city"/>
|
||||
<result property="address" column="address"/>
|
||||
<result property="grade" column="grade"/>
|
||||
<result property="source" column="source"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectBizClientList" resultMap="BaseRM">
|
||||
SELECT * FROM biz_client
|
||||
<where>
|
||||
<if test="tenantId != null"> AND tenant_id=#{tenantId}</if>
|
||||
<if test="clientName != null and clientName != ''">
|
||||
AND (client_name LIKE CONCAT('%',#{clientName},'%')
|
||||
OR client_no LIKE CONCAT('%',#{clientName},'%')
|
||||
OR contact LIKE CONCAT('%',#{clientName},'%'))
|
||||
</if>
|
||||
<if test="status != null and status != ''"> AND status=#{status}</if>
|
||||
</where>
|
||||
ORDER BY client_id DESC
|
||||
</select>
|
||||
|
||||
<select id="selectBizClientById" resultMap="BaseRM">
|
||||
SELECT * FROM biz_client WHERE client_id=#{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertBizClient" useGeneratedKeys="true" keyProperty="clientId">
|
||||
INSERT INTO biz_client(tenant_id,client_no,client_name,contact,phone,email,city,address,grade,source,status,create_by,create_time)
|
||||
VALUES(#{tenantId},#{clientNo},#{clientName},#{contact},#{phone},#{email},#{city},#{address},#{grade},#{source},#{status},#{createBy},NOW())
|
||||
</insert>
|
||||
|
||||
<update id="updateBizClient">
|
||||
UPDATE biz_client
|
||||
<set>
|
||||
<if test="clientNo != null">client_no=#{clientNo},</if>
|
||||
<if test="clientName != null">client_name=#{clientName},</if>
|
||||
<if test="contact != null">contact=#{contact},</if>
|
||||
<if test="phone != null">phone=#{phone},</if>
|
||||
<if test="email != null">email=#{email},</if>
|
||||
<if test="city != null">city=#{city},</if>
|
||||
<if test="address != null">address=#{address},</if>
|
||||
<if test="grade != null">grade=#{grade},</if>
|
||||
<if test="source != null">source=#{source},</if>
|
||||
<if test="status != null">status=#{status},</if>
|
||||
update_by=#{updateBy}, update_time=NOW()
|
||||
</set>
|
||||
WHERE client_id=#{clientId}
|
||||
</update>
|
||||
|
||||
<delete id="deleteBizClientById">DELETE FROM biz_client WHERE client_id=#{id}</delete>
|
||||
|
||||
<delete id="deleteBizClientByIds">
|
||||
DELETE FROM biz_client WHERE client_id IN
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</delete>
|
||||
|
||||
<select id="selectClientDeliveryOrders" resultType="java.util.Map">
|
||||
SELECT d.do_no,
|
||||
d.delivery_date,
|
||||
d.delay_date,
|
||||
d.actual_close_date,
|
||||
d.delivery_status,
|
||||
d.total_amount,
|
||||
s.supplier_name,
|
||||
(SELECT COUNT(*) FROM biz_delivery_order_item WHERE do_id = d.do_id) AS item_count
|
||||
FROM biz_client_quote cq
|
||||
JOIN biz_rfq r ON r.client_quote_id = cq.quote_id
|
||||
JOIN biz_delivery_order d ON d.rfq_id = r.rfq_id
|
||||
LEFT JOIN biz_supplier s ON d.supplier_id = s.supplier_id
|
||||
WHERE cq.client_id = #{clientId}
|
||||
ORDER BY d.create_time DESC
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.bid.BizDeliveryOrderItemMapper">
|
||||
<resultMap id="BaseRM" type="com.ruoyi.system.domain.bid.BizDeliveryOrderItem">
|
||||
<id property="itemId" column="item_id"/>
|
||||
<result property="doId" column="do_id"/>
|
||||
<result property="materialId" column="material_id"/>
|
||||
<result property="materialName" column="material_name"/>
|
||||
<result property="spec" column="spec"/>
|
||||
<result property="unit" column="unit"/>
|
||||
<result property="quantity" column="quantity"/>
|
||||
<result property="unitPrice" column="unit_price"/>
|
||||
<result property="totalPrice" column="total_price"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectItemsByDoId" resultMap="BaseRM">
|
||||
SELECT * FROM biz_delivery_order_item WHERE do_id=#{doId}
|
||||
</select>
|
||||
|
||||
<insert id="insertBizDeliveryOrderItem" useGeneratedKeys="true" keyProperty="itemId">
|
||||
INSERT INTO biz_delivery_order_item(do_id,material_id,material_name,spec,unit,quantity,unit_price,total_price,remark)
|
||||
VALUES(#{doId},#{materialId},#{materialName},#{spec},#{unit},#{quantity},#{unitPrice},#{totalPrice},#{remark})
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByDoId">DELETE FROM biz_delivery_order_item WHERE do_id=#{doId}</delete>
|
||||
</mapper>
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.system.mapper.bid.BizDeliveryOrderMapper">
|
||||
|
||||
<resultMap id="BaseRM" type="com.ruoyi.system.domain.bid.BizDeliveryOrder">
|
||||
<id property="doId" column="do_id"/>
|
||||
<result property="tenantId" column="tenant_id"/>
|
||||
<result property="doNo" column="do_no"/>
|
||||
<result property="rfqId" column="rfq_id"/>
|
||||
<result property="quotationId" column="quotation_id"/>
|
||||
<result property="supplierId" column="supplier_id"/>
|
||||
<result property="totalAmount" column="total_amount"/>
|
||||
<result property="currency" column="currency"/>
|
||||
<result property="deliveryDate" column="delivery_date"/>
|
||||
<result property="delayDate" column="delay_date"/>
|
||||
<result property="actualCloseDate" column="actual_close_date"/>
|
||||
<result property="closeDateSetBy" column="close_date_set_by"/>
|
||||
<result property="deliveryStatus" column="delivery_status"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="supplierName" column="supplier_name"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectBizDeliveryOrderList" resultMap="BaseRM">
|
||||
SELECT d.*, s.supplier_name
|
||||
FROM biz_delivery_order d
|
||||
LEFT JOIN biz_supplier s ON d.supplier_id=s.supplier_id
|
||||
<where>
|
||||
<if test="tenantId != null"> AND d.tenant_id=#{tenantId}</if>
|
||||
<if test="doNo != null and doNo != ''"> AND d.do_no LIKE CONCAT('%',#{doNo},'%')</if>
|
||||
<if test="supplierId != null"> AND d.supplier_id=#{supplierId}</if>
|
||||
<if test="deliveryStatus != null and deliveryStatus != ''"> AND d.delivery_status=#{deliveryStatus}</if>
|
||||
<if test="supplierName != null and supplierName != ''"> AND s.supplier_name LIKE CONCAT('%',#{supplierName},'%')</if>
|
||||
</where>
|
||||
ORDER BY d.create_time DESC
|
||||
</select>
|
||||
|
||||
<select id="selectBizDeliveryOrderById" resultMap="BaseRM">
|
||||
SELECT d.*, s.supplier_name
|
||||
FROM biz_delivery_order d
|
||||
LEFT JOIN biz_supplier s ON d.supplier_id=s.supplier_id
|
||||
WHERE d.do_id=#{id}
|
||||
</select>
|
||||
|
||||
<insert id="insertBizDeliveryOrder" useGeneratedKeys="true" keyProperty="doId">
|
||||
INSERT INTO biz_delivery_order(tenant_id,do_no,rfq_id,quotation_id,supplier_id,total_amount,currency,delivery_date,delay_date,actual_close_date,close_date_set_by,delivery_status,remark,create_by,create_time)
|
||||
VALUES(#{tenantId},#{doNo},#{rfqId},#{quotationId},#{supplierId},#{totalAmount},#{currency},#{deliveryDate},#{delayDate},#{actualCloseDate},#{closeDateSetBy},#{deliveryStatus},#{remark},#{createBy},NOW())
|
||||
</insert>
|
||||
|
||||
<update id="updateBizDeliveryOrder">
|
||||
UPDATE biz_delivery_order
|
||||
<set>
|
||||
<if test="doNo != null">do_no=#{doNo},</if>
|
||||
<if test="supplierId != null">supplier_id=#{supplierId},</if>
|
||||
<if test="totalAmount != null">total_amount=#{totalAmount},</if>
|
||||
<if test="deliveryDate != null">delivery_date=#{deliveryDate},</if>
|
||||
<if test="delayDate != null">delay_date=#{delayDate},</if>
|
||||
<if test="actualCloseDate != null">actual_close_date=#{actualCloseDate},</if>
|
||||
<if test="closeDateSetBy != null">close_date_set_by=#{closeDateSetBy},</if>
|
||||
<if test="deliveryStatus != null">delivery_status=#{deliveryStatus},</if>
|
||||
<if test="remark != null">remark=#{remark},</if>
|
||||
update_by=#{updateBy}, update_time=NOW()
|
||||
</set>
|
||||
WHERE do_id=#{doId}
|
||||
</update>
|
||||
|
||||
<delete id="deleteBizDeliveryOrderById">DELETE FROM biz_delivery_order WHERE do_id=#{id}</delete>
|
||||
|
||||
<delete id="deleteBizDeliveryOrderByIds">
|
||||
DELETE FROM biz_delivery_order WHERE do_id IN
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</delete>
|
||||
</mapper>
|
||||
8
ruoyi-ui/src/api/bid/client.js
Normal file
8
ruoyi-ui/src/api/bid/client.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import request from '@/utils/request'
|
||||
const baseUrl = '/bid/client'
|
||||
export const listClient = (params) => request({ url: baseUrl + '/list', method: 'get', params })
|
||||
export const getClient = (id) => request({ url: baseUrl + '/' + id, method: 'get' })
|
||||
export const addClient = (data) => request({ url: baseUrl, method: 'post', data })
|
||||
export const updateClient = (data) => request({ url: baseUrl, method: 'put', data })
|
||||
export const delClient = (ids) => request({ url: baseUrl + '/' + ids, method: 'delete' })
|
||||
export const getClientOrders = (id) => request({ url: baseUrl + '/' + id + '/orders', method: 'get' })
|
||||
11
ruoyi-ui/src/api/bid/delivery.js
Normal file
11
ruoyi-ui/src/api/bid/delivery.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import request from '@/utils/request'
|
||||
const baseUrl = '/bid/delivery'
|
||||
export const listDelivery = (params) => request({ url: baseUrl + '/list', method: 'get', params })
|
||||
export const getDelivery = (id) => request({ url: baseUrl + '/' + id, method: 'get' })
|
||||
export const addDelivery = (data) => request({ url: baseUrl, method: 'post', data })
|
||||
export const updateDelivery = (data) => request({ url: baseUrl, method: 'put', data })
|
||||
export const delDelivery = (ids) => request({ url: baseUrl + '/' + ids, method: 'delete' })
|
||||
export const shipDelivery = (id) => request({ url: baseUrl + '/' + id + '/ship', method: 'put' })
|
||||
export const completeDelivery = (id) => request({ url: baseUrl + '/' + id + '/complete', method: 'put' })
|
||||
export const recallDelivery = (id) => request({ url: baseUrl + '/' + id + '/recall', method: 'put' })
|
||||
export const setCloseDate = (id, closeDate) => request({ url: baseUrl + '/' + id + '/closeDate', method: 'put', params: { closeDate } })
|
||||
@@ -176,6 +176,19 @@ export const dynamicRoutes = [
|
||||
meta: { title: '甲方报价单详情', activeMenu: '/clientquote' }
|
||||
}]
|
||||
},
|
||||
// ── 甲方客户 ──
|
||||
{
|
||||
path: '/bid/client',
|
||||
component: Layout,
|
||||
permissions: ['bid:client:list'],
|
||||
children: [{
|
||||
path: '',
|
||||
component: () => import('@/views/bid/client/index'),
|
||||
name: 'Client',
|
||||
meta: { title: '甲方客户', activeMenu: '/bid/client' }
|
||||
}]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/bid/comparison/detail',
|
||||
component: Layout,
|
||||
|
||||
350
ruoyi-ui/src/views/bid/client/index.vue
Normal file
350
ruoyi-ui/src/views/bid/client/index.vue
Normal file
@@ -0,0 +1,350 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-tabs v-model="activeTab">
|
||||
<!-- ═══════════ Tab 1: 客户列表 ═══════════ -->
|
||||
<el-tab-pane label="客户列表" name="list">
|
||||
<div class="toolbar">
|
||||
<el-input
|
||||
v-model="queryParams.clientName"
|
||||
placeholder="搜索名称/编号/联系人"
|
||||
size="small"
|
||||
clearable
|
||||
style="width:320px"
|
||||
prefix-icon="el-icon-search"
|
||||
@keyup.enter.native="handleSearch"
|
||||
/>
|
||||
<el-button type="primary" size="small" icon="el-icon-search" @click="handleSearch">搜索</el-button>
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">新增客户</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="clientList" border size="small" style="width:100%">
|
||||
<el-table-column label="编号" prop="clientNo" width="100" />
|
||||
<el-table-column label="名称" prop="clientName" min-width="160" />
|
||||
<el-table-column label="联系人" prop="contact" width="100" />
|
||||
<el-table-column label="电话" prop="phone" width="130" />
|
||||
<el-table-column label="城市" prop="city" width="110" />
|
||||
<el-table-column label="订单数" prop="orderCount" width="80" align="center" />
|
||||
<el-table-column label="备注" prop="remark" min-width="120" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作" width="140" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEdit(scope.row)">编辑</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#f56c6c" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ═══════════ Tab 2: 历史发货单 ═══════════ -->
|
||||
<el-tab-pane label="历史发货单" name="orders">
|
||||
<div class="toolbar">
|
||||
<el-select v-model="orderClientId" filterable placeholder="选择甲方客户" style="width:400px" @change="loadClientOrders" clearable>
|
||||
<el-option v-for="c in clientOptions" :key="c.clientId" :label="c.clientNo + ' | ' + c.clientName" :value="c.clientId" />
|
||||
</el-select>
|
||||
<span v-if="orderClientName" style="margin-left:12px;color:#909399;font-size:12px">共 {{ orderList.length }} 条记录</span>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="orderLoading" :data="orderList" border size="small" style="width:100%">
|
||||
<el-table-column label="发货单号" prop="doNo" width="150" />
|
||||
<el-table-column label="供应商" prop="supplierName" min-width="140" />
|
||||
<el-table-column label="金额" width="130" align="right">
|
||||
<template slot-scope="scope">¥{{ scope.row.totalAmount }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="交货期" prop="deliveryDate" width="100" />
|
||||
<el-table-column label="结单日期" prop="actualCloseDate" width="100" />
|
||||
<el-table-column label="物料数" prop="itemCount" width="70" align="center" />
|
||||
<el-table-column label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="statusType(scope.row.deliveryStatus)" size="small">{{ statusLabel(scope.row.deliveryStatus) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="showOrderDetail(scope.row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-empty v-if="!orderClientId && !orderLoading" description="请先选择甲方客户" />
|
||||
<el-empty v-if="orderClientId && !orderList.length && !orderLoading" description="该客户暂无发货记录" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- ═══════════ 新增/编辑客户弹窗 ═══════════ -->
|
||||
<el-dialog :title="dialogTitle" :visible.sync="dialogOpen" width="600px" append-to-body @close="cancelDialog">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="90px" size="small">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户编号" prop="clientNo">
|
||||
<el-input v-model="form.clientNo" placeholder="如 CU-001" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户名称" prop="clientName">
|
||||
<el-input v-model="form.clientName" placeholder="客户企业名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系人" prop="contact">
|
||||
<el-input v-model="form.contact" placeholder="联系人姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="联系电话" prop="phone">
|
||||
<el-input v-model="form.phone" placeholder="手机号/固话" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="电子邮箱" prop="email">
|
||||
<el-input v-model="form.email" placeholder="电子邮箱" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="所在城市" prop="city">
|
||||
<el-input v-model="form.city" placeholder="如 广东深圳" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="详细地址" prop="address">
|
||||
<el-input v-model="form.address" placeholder="详细地址" />
|
||||
</el-form-item>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户等级" prop="grade">
|
||||
<el-select v-model="form.grade" style="width:100%">
|
||||
<el-option label="A级" value="A" />
|
||||
<el-option label="B级" value="B" />
|
||||
<el-option label="C级" value="C" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="form.status" style="width:100%">
|
||||
<el-option label="正常" value="0" />
|
||||
<el-option label="停用" value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="备注信息" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="cancelDialog">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- ═══════════ 发货单详情弹窗 ═══════════ -->
|
||||
<el-dialog title="发货单详情" :visible.sync="detailOpen" width="780px" append-to-body>
|
||||
<div v-if="detailData" class="detail-card">
|
||||
<div class="detail-section">
|
||||
<table class="detail-table">
|
||||
<tr>
|
||||
<td class="dt-label">发货单号</td><td class="dt-value"><b>{{ detailData.doNo }}</b></td>
|
||||
<td class="dt-label">供应商</td><td class="dt-value">{{ detailData.supplierName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dt-label">总金额</td><td class="dt-value" style="color:#409EFF;font-weight:700">¥{{ detailData.totalAmount }}</td>
|
||||
<td class="dt-label">状态</td>
|
||||
<td class="dt-value">
|
||||
<el-tag :type="statusType(detailData.deliveryStatus)" size="small">{{ statusLabel(detailData.deliveryStatus) }}</el-tag>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="dt-label">交货期</td><td class="dt-value">{{ detailData.deliveryDate || '-' }}</td>
|
||||
<td class="dt-label">结单日期</td><td class="dt-value">{{ detailData.actualCloseDate || '-' }}</td>
|
||||
</tr>
|
||||
<tr v-if="detailData.remark">
|
||||
<td class="dt-label">备注</td><td class="dt-value" colspan="3">{{ detailData.remark }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="detail-section">
|
||||
<div class="section-title">物料明细</div>
|
||||
<el-table :data="detailData.items || []" border size="small" style="width:100%">
|
||||
<el-table-column label="物料名称" prop="materialName" min-width="140" />
|
||||
<el-table-column label="规格" prop="spec" width="120" />
|
||||
<el-table-column label="单位" prop="unit" width="60" />
|
||||
<el-table-column label="数量" prop="quantity" width="80" align="right" />
|
||||
<el-table-column label="单价" width="100" align="right">
|
||||
<template slot-scope="s">¥{{ s.row.unitPrice }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="小计" width="100" align="right">
|
||||
<template slot-scope="s">¥{{ s.row.totalPrice }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer">
|
||||
<el-button @click="detailOpen = false">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listClient, getClient, addClient, updateClient, delClient, getClientOrders } from "@/api/bid/client"
|
||||
import { getDelivery } from "@/api/bid/delivery"
|
||||
|
||||
export default {
|
||||
name: "Client",
|
||||
data() {
|
||||
return {
|
||||
// ── Tab ──
|
||||
activeTab: "list",
|
||||
|
||||
// ── 客户列表 ──
|
||||
loading: false,
|
||||
clientList: [],
|
||||
total: 0,
|
||||
queryParams: { pageNum: 1, pageSize: 20, clientName: "" },
|
||||
|
||||
// ── 新增/编辑 ──
|
||||
dialogOpen: false,
|
||||
dialogTitle: "",
|
||||
form: { grade: "B", status: "0" },
|
||||
rules: {
|
||||
clientNo: [{ required: true, message: "客户编号不能为空", trigger: "blur" }],
|
||||
clientName: [{ required: true, message: "客户名称不能为空", trigger: "blur" }]
|
||||
},
|
||||
editId: null,
|
||||
|
||||
// ── 历史发货单 ──
|
||||
orderClientId: null,
|
||||
orderClientName: "",
|
||||
orderLoading: false,
|
||||
orderList: [],
|
||||
clientOptions: [],
|
||||
|
||||
// ── 发货单详情 ──
|
||||
detailOpen: false,
|
||||
detailData: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
this.loadClientOptions()
|
||||
},
|
||||
methods: {
|
||||
// ═══════════ 客户列表 ═══════════
|
||||
getList() {
|
||||
this.loading = true
|
||||
listClient(this.queryParams).then(r => {
|
||||
this.clientList = r.rows || []
|
||||
this.total = r.total || 0
|
||||
this.loading = false
|
||||
}).catch(() => { this.loading = false })
|
||||
},
|
||||
handleSearch() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
this.loadClientOptions()
|
||||
},
|
||||
|
||||
// ═══════════ 新增/编辑 ═══════════
|
||||
handleAdd() {
|
||||
this.editId = null
|
||||
this.form = { grade: "B", status: "0", clientNo: "", clientName: "", contact: "", phone: "", email: "", city: "", address: "", remark: "" }
|
||||
this.dialogTitle = "新增客户"
|
||||
this.dialogOpen = true
|
||||
},
|
||||
handleEdit(row) {
|
||||
this.editId = row.clientId
|
||||
this.form = { ...row }
|
||||
this.dialogTitle = "编辑客户"
|
||||
this.dialogOpen = true
|
||||
},
|
||||
cancelDialog() {
|
||||
this.dialogOpen = false
|
||||
this.$refs.form && this.$refs.form.clearValidate()
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
const action = this.editId ? updateClient(this.form) : addClient(this.form)
|
||||
action.then(() => {
|
||||
this.$modal.msgSuccess(this.editId ? "修改成功" : "新增成功")
|
||||
this.dialogOpen = false
|
||||
this.getList()
|
||||
}).catch(() => {})
|
||||
})
|
||||
},
|
||||
|
||||
// ═══════════ 删除 ═══════════
|
||||
handleDelete(row) {
|
||||
this.$modal.confirm('确认删除客户 "' + row.clientName + '"?').then(() => {
|
||||
delClient(row.clientId).then(() => {
|
||||
this.$modal.msgSuccess("删除成功")
|
||||
this.getList()
|
||||
})
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// ═══════════ 历史发货单 ═══════════
|
||||
loadClientOptions() {
|
||||
listClient({ pageNum: 1, pageSize: 999 }).then(r => {
|
||||
this.clientOptions = r.rows || []
|
||||
}).catch(() => {})
|
||||
},
|
||||
loadClientOrders(clientId) {
|
||||
if (!clientId) {
|
||||
this.orderList = []
|
||||
this.orderClientName = ""
|
||||
return
|
||||
}
|
||||
this.orderLoading = true
|
||||
this.orderList = []
|
||||
// 获取客户名用于显示
|
||||
const c = this.clientOptions.find(o => o.clientId === clientId)
|
||||
this.orderClientName = c ? c.clientName : ""
|
||||
getClientOrders(clientId).then(r => {
|
||||
this.orderList = (r.data || []).map(o => ({
|
||||
...o,
|
||||
totalAmount: o.totalAmount || o.total_amount,
|
||||
deliveryDate: o.deliveryDate || o.delivery_date,
|
||||
actualCloseDate: o.actualCloseDate || o.actual_close_date,
|
||||
deliveryStatus: o.deliveryStatus || o.delivery_status,
|
||||
itemCount: o.itemCount || o.item_count
|
||||
}))
|
||||
this.orderLoading = false
|
||||
}).catch(() => { this.orderLoading = false })
|
||||
},
|
||||
|
||||
// ═══════════ 发货单详情 ═══════════
|
||||
showOrderDetail(row) {
|
||||
getDelivery(row.doId || row.do_id).then(r => {
|
||||
this.detailData = r.data
|
||||
this.detailOpen = true
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// ═══════════ 工具方法 ═══════════
|
||||
statusType(s) {
|
||||
return { pending: "warning", transit: "primary", history: "success" }[s] || ""
|
||||
},
|
||||
statusLabel(s) {
|
||||
return { pending: "待发", transit: "在途", history: "已收货" }[s] || s || "-"
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-container { background: #fff; padding: 20px; border-radius: 4px; min-height: calc(100vh - 104px); }
|
||||
.toolbar { margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
|
||||
.detail-card { padding: 0; }
|
||||
.detail-section { margin-bottom: 20px; }
|
||||
.section-title { font-size: 14px; font-weight: 700; color: #1a2c4e; margin-bottom: 10px; padding-left: 8px; border-left: 4px solid #1171c4; }
|
||||
.detail-table { width: 100%; border-collapse: collapse; }
|
||||
.detail-table td { padding: 8px 12px; border: 1px solid #e4e7ed; }
|
||||
.dt-label { background: #f5f7fa; color: #606266; font-weight: 600; width: 90px; font-size: 12px; }
|
||||
.dt-value { color: #303133; font-size: 13px; }
|
||||
</style>
|
||||
114
sql/fix_menu_all.sql
Normal file
114
sql/fix_menu_all.sql
Normal file
@@ -0,0 +1,114 @@
|
||||
-- ============================================================
|
||||
-- 菜单全面修复脚本
|
||||
-- 1. 修复所有乱码菜单名称(根据 perms 字段还原)
|
||||
-- 2. 新增菜单移至主目录(parent_id=0),因 智慧报价(2000) 已停用
|
||||
-- 3. 插入缺失的菜单条目
|
||||
-- ============================================8===============
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 第一部分:修复所有乱码菜单名称
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
-- bid 模块主菜单(parent_id=0 且无 perms 的父节点)
|
||||
UPDATE sys_menu SET menu_name = '智慧报价' WHERE menu_id = 2000;
|
||||
|
||||
-- bid 模块子菜单
|
||||
UPDATE sys_menu SET menu_name = '物料管理' WHERE perms = 'bid:material:list';
|
||||
UPDATE sys_menu SET menu_name = '新增' WHERE perms = 'bid:material:add' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '编辑' WHERE perms = 'bid:material:edit' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '删除' WHERE perms = 'bid:material:remove' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '查询' WHERE perms = 'bid:material:query' AND menu_type = 'F';
|
||||
|
||||
UPDATE sys_menu SET menu_name = '供应商管理' WHERE perms = 'bid:supplier:list';
|
||||
UPDATE sys_menu SET menu_name = '供应商报价' WHERE perms = 'bid:quotation:list';
|
||||
UPDATE sys_menu SET menu_name = '报价请求' WHERE perms = 'bid:rfq:list';
|
||||
UPDATE sys_menu SET menu_name = '智慧比价' WHERE perms = 'bid:comparison:list';
|
||||
UPDATE sys_menu SET menu_name = '采购单' WHERE perms = 'bid:purchaseorder:list';
|
||||
UPDATE sys_menu SET menu_name = '供应商评价' WHERE perms = 'bid:evaluation:list';
|
||||
UPDATE sys_menu SET menu_name = '订单异议' WHERE perms = 'bid:objection:list';
|
||||
UPDATE sys_menu SET menu_name = '交易记录' WHERE perms = 'bid:transaction:list';
|
||||
UPDATE sys_menu SET menu_name = '租户管理' WHERE perms = 'bid:tenant:list';
|
||||
|
||||
-- 甲方报价单
|
||||
UPDATE sys_menu SET menu_name = '甲方报价' WHERE perms = 'bid:clientquote:list';
|
||||
UPDATE sys_menu SET menu_name = '新增报价' WHERE perms = 'bid:clientquote:add' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '编辑报价' WHERE perms = 'bid:clientquote:edit' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '删除报价' WHERE perms = 'bid:clientquote:remove' AND menu_type = 'F';
|
||||
|
||||
-- 统计分析
|
||||
UPDATE sys_menu SET menu_name = '统计分析' WHERE perms = 'bid:report:list';
|
||||
UPDATE sys_menu SET menu_name = '采购总览看板' WHERE perms = 'bid:report:dashboard';
|
||||
UPDATE sys_menu SET menu_name = '采购成本分析' WHERE perms = 'bid:report:cost';
|
||||
UPDATE sys_menu SET menu_name = '供应商绩效' WHERE perms = 'bid:report:supplier';
|
||||
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 第二部分:修复我们的新菜单名称
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
UPDATE sys_menu SET menu_name = '订单履约' WHERE perms = 'bid:order:list';
|
||||
UPDATE sys_menu SET menu_name = '待发订单' WHERE perms = 'bid:order:pending';
|
||||
UPDATE sys_menu SET menu_name = '历史订单' WHERE perms = 'bid:order:history';
|
||||
UPDATE sys_menu SET menu_name = '结单时间管理' WHERE perms = 'bid:order:closeDate';
|
||||
UPDATE sys_menu SET menu_name = '甲方客户' WHERE perms = 'bid:client:list';
|
||||
UPDATE sys_menu SET menu_name = '编辑客户' WHERE perms = 'bid:client:edit' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '删除客户' WHERE perms = 'bid:client:remove' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '结单录入' WHERE perms = 'bid:order:closeDate:edit' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '操作记录' WHERE perms = 'bid:operationlog:list';
|
||||
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 第三部分:将新菜单移至主目录(parent_id=0)
|
||||
-- 因为 智慧报价(2000) 已停用,其下的子菜单不可见
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
-- 订单履约(2023) → 根目录,排序20
|
||||
UPDATE sys_menu SET parent_id = 0, order_num = 20 WHERE menu_id = 2023;
|
||||
-- 甲方客户(2028) → 根目录,排序21
|
||||
UPDATE sys_menu SET parent_id = 0, order_num = 21 WHERE menu_id = 2028;
|
||||
-- 操作记录(2029) → 根目录,排序22
|
||||
UPDATE sys_menu SET parent_id = 0, order_num = 22 WHERE menu_id = 2029;
|
||||
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 第四部分:插入缺失的菜单条目
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
-- 在途订单 (2025)
|
||||
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(2025, '在途订单', 2023, 2, 'transit', 'bid/order/transit', 1, 0, 'C', '0', '0', 'bid:order:transit', 'truck', 'admin', NOW());
|
||||
|
||||
-- 新增客户按钮 (2030)
|
||||
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(2030, '新增客户', 2028, 1, '#', NULL, 1, 0, 'F', '0', '0', 'bid:client:add', '#', 'admin', NOW());
|
||||
|
||||
-- 查询客户按钮 (2033)
|
||||
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(2033, '查询客户', 2028, 4, '#', NULL, 1, 0, 'F', '0', '0', 'bid:client:query', '#', 'admin', NOW());
|
||||
|
||||
-- 订单查询按钮 (2034)
|
||||
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(2034, '订单查询', 2024, 1, '#', NULL, 1, 0, 'F', '0', '0', 'bid:order:query', '#', 'admin', NOW());
|
||||
|
||||
-- 订单状态变更按钮 (2035)
|
||||
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(2035, '订单状态变更', 2024, 2, '#', NULL, 1, 0, 'F', '0', '0', 'bid:order:status', '#', 'admin', NOW());
|
||||
|
||||
-- 操作记录查询按钮 (2037)
|
||||
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(2037, '操作记录查询', 2029, 1, '#', NULL, 1, 0, 'F', '0', '0', 'bid:operationlog:query', '#', 'admin', NOW());
|
||||
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 第五部分:角色-菜单关联(确保 admin 有权限)
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
INSERT IGNORE INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT 1, menu_id FROM sys_menu WHERE menu_id IN (2025, 2030, 2033, 2034, 2035, 2037);
|
||||
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 验证
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
SELECT menu_id, menu_name, parent_id, perms, order_num,
|
||||
CASE WHEN status='0' THEN '正常' ELSE '停用' END AS status
|
||||
FROM sys_menu WHERE menu_id BETWEEN 2000 AND 2037
|
||||
ORDER BY menu_id;
|
||||
30
sql/fix_menu_garbled.sql
Normal file
30
sql/fix_menu_garbled.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- 修复菜单名称乱码问题
|
||||
-- 根据截图中显示的权限字符,还原正确的菜单名称
|
||||
|
||||
-- 订单管理相关菜单
|
||||
UPDATE sys_menu SET menu_name = '订单管理' WHERE perms = 'bid:order:list' AND menu_name LIKE '%璁㈠%';
|
||||
UPDATE sys_menu SET menu_name = '待发订单' WHERE perms = 'bid:order:pending' AND menu_name LIKE '%寰%';
|
||||
UPDATE sys_menu SET menu_name = '在途订单' WHERE perms = 'bid:order:transit' AND menu_name LIKE '%鍦ㄩ%';
|
||||
UPDATE sys_menu SET menu_name = '历史订单' WHERE perms = 'bid:order:history' AND menu_name LIKE '%鍘嗗彶%';
|
||||
UPDATE sys_menu SET menu_name = '结单时间' WHERE perms = 'bid:order:closeDate' AND menu_name LIKE '%缁撳崟%';
|
||||
|
||||
-- 甲方客户管理
|
||||
UPDATE sys_menu SET menu_name = '甲方客户' WHERE perms = 'bid:client:list' AND menu_name LIKE '%鐢插彛%';
|
||||
|
||||
-- 操作记录
|
||||
UPDATE sys_menu SET menu_name = '操作记录' WHERE perms = 'bid:operationlog:list' AND menu_name LIKE '%鎿嶄綔%';
|
||||
UPDATE sys_menu SET menu_name = '查询' WHERE perms = 'bid:operationlog:query' AND menu_name LIKE '%鏌ヨ%';
|
||||
|
||||
-- 如果上述更新没有匹配到,使用menu_id直接更新(根据截图中的排序号判断)
|
||||
-- 订单管理目录(排序号10)
|
||||
UPDATE sys_menu SET menu_name = '订单管理' WHERE menu_id IN (
|
||||
SELECT menu_id FROM (SELECT menu_id FROM sys_menu WHERE parent_id = 0 AND order_num = 10) AS t
|
||||
);
|
||||
|
||||
-- 查询更新结果
|
||||
SELECT menu_id, menu_name, perms, order_num
|
||||
FROM sys_menu
|
||||
WHERE perms LIKE 'bid:order:%' OR perms LIKE 'bid:client:%' OR perms LIKE 'bid:operationlog:%'
|
||||
ORDER BY menu_id;
|
||||
74
sql/fix_menu_garbled_complete.sql
Normal file
74
sql/fix_menu_garbled_complete.sql
Normal file
@@ -0,0 +1,74 @@
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ============================================
|
||||
-- 菜单名称乱码修复脚本
|
||||
-- 根据权限字符(perms)和菜单类型还原正确的菜单名称
|
||||
-- ============================================
|
||||
|
||||
-- 1. 订单管理模块
|
||||
UPDATE sys_menu SET menu_name = '订单管理' WHERE perms = 'bid:order:list';
|
||||
UPDATE sys_menu SET menu_name = '待发订单' WHERE perms = 'bid:order:pending';
|
||||
UPDATE sys_menu SET menu_name = '在途订单' WHERE perms = 'bid:order:transit';
|
||||
UPDATE sys_menu SET menu_name = '历史订单' WHERE perms = 'bid:order:history';
|
||||
UPDATE sys_menu SET menu_name = '结单时间' WHERE perms = 'bid:order:closeDate';
|
||||
|
||||
-- 2. 甲方客户管理
|
||||
UPDATE sys_menu SET menu_name = '甲方客户' WHERE perms = 'bid:client:list';
|
||||
|
||||
-- 3. 操作记录
|
||||
UPDATE sys_menu SET menu_name = '操作记录' WHERE perms = 'bid:operationlog:list';
|
||||
UPDATE sys_menu SET menu_name = '查询' WHERE perms = 'bid:operationlog:query' AND menu_type = 'F';
|
||||
|
||||
-- 4. 甲方报价(如果有乱码)
|
||||
UPDATE sys_menu SET menu_name = '甲方报价' WHERE perms = 'bid:clientquote:list';
|
||||
UPDATE sys_menu SET menu_name = '新增' WHERE perms = 'bid:clientquote:add' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '编辑' WHERE perms = 'bid:clientquote:edit' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '删除' WHERE perms = 'bid:clientquote:remove' AND menu_type = 'F';
|
||||
UPDATE sys_menu SET menu_name = '导出' WHERE perms = 'bid:clientquote:export' AND menu_type = 'F';
|
||||
|
||||
-- 5. 报价请求(RFQ)
|
||||
UPDATE sys_menu SET menu_name = '报价请求' WHERE perms = 'bid:rfq:list';
|
||||
|
||||
-- 6. 供应商管理
|
||||
UPDATE sys_menu SET menu_name = '供应商管理' WHERE perms = 'bid:supplier:list';
|
||||
|
||||
-- 7. 物料管理
|
||||
UPDATE sys_menu SET menu_name = '物料管理' WHERE perms = 'bid:material:list';
|
||||
|
||||
-- 8. 智慧比价
|
||||
UPDATE sys_menu SET menu_name = '智慧比价' WHERE perms = 'bid:comparison:list';
|
||||
|
||||
-- 9. 统计分析
|
||||
UPDATE sys_menu SET menu_name = '统计分析' WHERE perms = 'bid:report:list';
|
||||
|
||||
-- 10. 采购单
|
||||
UPDATE sys_menu SET menu_name = '采购单' WHERE perms = 'bid:purchaseorder:list';
|
||||
|
||||
-- 11. 供应商评价
|
||||
UPDATE sys_menu SET menu_name = '供应商评价' WHERE perms = 'bid:evaluation:list';
|
||||
|
||||
-- 12. 交易记录
|
||||
UPDATE sys_menu SET menu_name = '交易记录' WHERE perms = 'bid:transaction:list';
|
||||
|
||||
-- ============================================
|
||||
-- 验证修复结果
|
||||
-- ============================================
|
||||
|
||||
SELECT
|
||||
menu_id,
|
||||
menu_name,
|
||||
perms,
|
||||
menu_type,
|
||||
CASE menu_type
|
||||
WHEN 'M' THEN '目录'
|
||||
WHEN 'C' THEN '菜单'
|
||||
WHEN 'F' THEN '按钮'
|
||||
END AS type_name,
|
||||
order_num,
|
||||
status
|
||||
FROM sys_menu
|
||||
WHERE perms LIKE 'bid:%'
|
||||
ORDER BY menu_id;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
13
sql/fix_remaining.sql
Normal file
13
sql/fix_remaining.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
UPDATE sys_menu SET menu_name = '在途订单' WHERE perms = 'bid:order:transit';
|
||||
UPDATE sys_menu SET menu_name = '新增客户' WHERE menu_id = 2030;
|
||||
UPDATE sys_menu SET menu_name = '查询客户' WHERE menu_id = 2033;
|
||||
UPDATE sys_menu SET menu_name = '订单查询' WHERE menu_id = 2034;
|
||||
UPDATE sys_menu SET menu_name = '订单状态变更' WHERE menu_id = 2035;
|
||||
UPDATE sys_menu SET menu_name = '操作记录查询' WHERE menu_id = 2037;
|
||||
|
||||
SELECT '✅ 修复结果' AS '';
|
||||
SELECT menu_id, menu_name, perms FROM sys_menu
|
||||
WHERE menu_id IN (2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037)
|
||||
ORDER BY menu_id;
|
||||
Reference in New Issue
Block a user