Showing
5 changed files
with
245 additions
and
17 deletions
| ... | @@ -2,7 +2,9 @@ package com.apple.erp.service.impl; | ... | @@ -2,7 +2,9 @@ package com.apple.erp.service.impl; |
| 2 | 2 | ||
| 3 | import com.apple.erp.dto.*; | 3 | import com.apple.erp.dto.*; |
| 4 | import com.apple.erp.entity.DeliveryItem; | 4 | import com.apple.erp.entity.DeliveryItem; |
| 5 | +import com.apple.erp.entity.OrderMain; | ||
| 5 | import com.apple.erp.mapper.DeliveryItemMapper; | 6 | import com.apple.erp.mapper.DeliveryItemMapper; |
| 7 | +import com.apple.erp.mapper.OrderMainMapper; | ||
| 6 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 8 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| 7 | import com.baomidou.mybatisplus.core.metadata.IPage; | 9 | import com.baomidou.mybatisplus.core.metadata.IPage; |
| 8 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; | 10 | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| ... | @@ -36,6 +38,9 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del | ... | @@ -36,6 +38,9 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del |
| 36 | @Autowired | 38 | @Autowired |
| 37 | private DeliveryItemMapper deliveryItemMapper; | 39 | private DeliveryItemMapper deliveryItemMapper; |
| 38 | 40 | ||
| 41 | + @Autowired | ||
| 42 | + private OrderMainMapper orderMainMapper; | ||
| 43 | + | ||
| 39 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | 44 | private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
| 40 | 45 | ||
| 41 | @Override | 46 | @Override |
| ... | @@ -107,6 +112,11 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del | ... | @@ -107,6 +112,11 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del |
| 107 | throw new IllegalArgumentException("出库单编号已存在"); | 112 | throw new IllegalArgumentException("出库单编号已存在"); |
| 108 | } | 113 | } |
| 109 | 114 | ||
| 115 | + // 验证关联的订单号是否在订单管理中存在 | ||
| 116 | + if (!isOrderNoExist(addReq.getOrderNo())) { | ||
| 117 | + throw new IllegalArgumentException("关联的订单编号不存在"); | ||
| 118 | + } | ||
| 119 | + | ||
| 110 | DeliveryMain deliveryMain = new DeliveryMain(); | 120 | DeliveryMain deliveryMain = new DeliveryMain(); |
| 111 | BeanUtils.copyProperties(addReq, deliveryMain); | 121 | BeanUtils.copyProperties(addReq, deliveryMain); |
| 112 | deliveryMain.setCreateTime(LocalDateTime.now()); | 122 | deliveryMain.setCreateTime(LocalDateTime.now()); |
| ... | @@ -141,6 +151,11 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del | ... | @@ -141,6 +151,11 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del |
| 141 | throw new IllegalArgumentException("出库单编号已存在"); | 151 | throw new IllegalArgumentException("出库单编号已存在"); |
| 142 | } | 152 | } |
| 143 | 153 | ||
| 154 | + // 验证关联的订单号是否在订单管理中存在 | ||
| 155 | + if (!isOrderNoExist(updateReq.getOrderNo())) { | ||
| 156 | + throw new IllegalArgumentException("关联的订单编号不存在"); | ||
| 157 | + } | ||
| 158 | + | ||
| 144 | DeliveryMain deliveryMain = new DeliveryMain(); | 159 | DeliveryMain deliveryMain = new DeliveryMain(); |
| 145 | BeanUtils.copyProperties(updateReq, deliveryMain); | 160 | BeanUtils.copyProperties(updateReq, deliveryMain); |
| 146 | deliveryMain.setUpdateTime(LocalDateTime.now()); | 161 | deliveryMain.setUpdateTime(LocalDateTime.now()); |
| ... | @@ -216,6 +231,18 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del | ... | @@ -216,6 +231,18 @@ public class DeliveryMainServiceImpl extends ServiceImpl<DeliveryMainMapper, Del |
| 216 | return baseMapper.selectCount(queryWrapper) > 0; | 231 | return baseMapper.selectCount(queryWrapper) > 0; |
| 217 | } | 232 | } |
| 218 | 233 | ||
| 234 | + /** | ||
| 235 | + * 检查订单编号是否在订单管理中存在 | ||
| 236 | + * @param orderNo 订单编号 | ||
| 237 | + * @return 是否存在 | ||
| 238 | + */ | ||
| 239 | + private boolean isOrderNoExist(String orderNo) { | ||
| 240 | + LambdaQueryWrapper<OrderMain> queryWrapper = Wrappers.lambdaQuery(OrderMain.class) | ||
| 241 | + .eq(OrderMain::getOrderNo, orderNo) | ||
| 242 | + .eq(OrderMain::getDelFlag, "0"); | ||
| 243 | + return orderMainMapper.selectCount(queryWrapper) > 0; | ||
| 244 | + } | ||
| 245 | + | ||
| 219 | private LocalDateTime parseDateTime(String dateTimeStr) { | 246 | private LocalDateTime parseDateTime(String dateTimeStr) { |
| 220 | if (!StringUtils.hasText(dateTimeStr)) { | 247 | if (!StringUtils.hasText(dateTimeStr)) { |
| 221 | return null; | 248 | return null; | ... | ... |
| ... | @@ -9,18 +9,29 @@ declare module 'vue' { | ... | @@ -9,18 +9,29 @@ declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | ElButton: typeof import('element-plus/es')['ElButton'] | 10 | ElButton: typeof import('element-plus/es')['ElButton'] |
| 11 | ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] | 11 | ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] |
| 12 | + ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] | ||
| 13 | + ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] | ||
| 12 | ElDialog: typeof import('element-plus/es')['ElDialog'] | 14 | ElDialog: typeof import('element-plus/es')['ElDialog'] |
| 13 | ElForm: typeof import('element-plus/es')['ElForm'] | 15 | ElForm: typeof import('element-plus/es')['ElForm'] |
| 14 | ElFormItem: typeof import('element-plus/es')['ElFormItem'] | 16 | ElFormItem: typeof import('element-plus/es')['ElFormItem'] |
| 17 | + ElIcon: typeof import('element-plus/es')['ElIcon'] | ||
| 15 | ElInput: typeof import('element-plus/es')['ElInput'] | 18 | ElInput: typeof import('element-plus/es')['ElInput'] |
| 19 | + ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] | ||
| 16 | ElOption: typeof import('element-plus/es')['ElOption'] | 20 | ElOption: typeof import('element-plus/es')['ElOption'] |
| 21 | + ElPagination: typeof import('element-plus/es')['ElPagination'] | ||
| 22 | + ElRadio: typeof import('element-plus/es')['ElRadio'] | ||
| 23 | + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] | ||
| 17 | ElSelect: typeof import('element-plus/es')['ElSelect'] | 24 | ElSelect: typeof import('element-plus/es')['ElSelect'] |
| 18 | ElTable: typeof import('element-plus/es')['ElTable'] | 25 | ElTable: typeof import('element-plus/es')['ElTable'] |
| 19 | ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] | 26 | ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] |
| 27 | + ElTag: typeof import('element-plus/es')['ElTag'] | ||
| 20 | Header: typeof import('./src/components/layout/Header.vue')['default'] | 28 | Header: typeof import('./src/components/layout/Header.vue')['default'] |
| 21 | RouterLink: typeof import('vue-router')['RouterLink'] | 29 | RouterLink: typeof import('vue-router')['RouterLink'] |
| 22 | RouterView: typeof import('vue-router')['RouterView'] | 30 | RouterView: typeof import('vue-router')['RouterView'] |
| 23 | Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] | 31 | Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] |
| 24 | SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default'] | 32 | SidebarItem: typeof import('./src/components/layout/SidebarItem.vue')['default'] |
| 25 | } | 33 | } |
| 34 | + export interface ComponentCustomProperties { | ||
| 35 | + vLoading: typeof import('element-plus/es')['ElLoadingDirective'] | ||
| 36 | + } | ||
| 26 | } | 37 | } | ... | ... |
| ... | @@ -51,6 +51,10 @@ export interface DealerInfo { | ... | @@ -51,6 +51,10 @@ export interface DealerInfo { |
| 51 | cooperationAgreementUrl: string | 51 | cooperationAgreementUrl: string |
| 52 | qualificationAuditStatus: number | 52 | qualificationAuditStatus: number |
| 53 | auditOpinion: string | 53 | auditOpinion: string |
| 54 | + totalRebateAmount?: number | ||
| 55 | + usedRebateAmount?: number | ||
| 56 | + pendingRebateAmount?: number | ||
| 57 | + lastRebateUpdateTime?: string | ||
| 54 | createTime: string | 58 | createTime: string |
| 55 | updateTime: string | 59 | updateTime: string |
| 56 | } | 60 | } | ... | ... |
| 1 | -import request from '@/utils/request' | 1 | +import axios from 'axios' |
| 2 | 2 | ||
| 3 | -/** | 3 | +const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8083' |
| 4 | - * 字典管理API | ||
| 5 | - */ | ||
| 6 | 4 | ||
| 7 | -// 获取字典项 | 5 | +const api = axios.create({ |
| 8 | -export const getDictItems = (dictType: string) => { | 6 | + baseURL: API_BASE_URL, |
| 9 | - return request.get(`/api/dict/${dictType}`) | 7 | + timeout: 10000, |
| 8 | + headers: { | ||
| 9 | + 'Content-Type': 'application/json' | ||
| 10 | + } | ||
| 11 | +}) | ||
| 12 | + | ||
| 13 | +api.interceptors.request.use( | ||
| 14 | + (config) => { | ||
| 15 | + const token = localStorage.getItem('token') | ||
| 16 | + if (token) { | ||
| 17 | + config.headers.Authorization = `Bearer ${token}` | ||
| 18 | + } | ||
| 19 | + return config | ||
| 20 | + }, | ||
| 21 | + (error) => { | ||
| 22 | + return Promise.reject(error) | ||
| 23 | + } | ||
| 24 | +) | ||
| 25 | + | ||
| 26 | +api.interceptors.response.use( | ||
| 27 | + (response) => { | ||
| 28 | + return response.data | ||
| 29 | + }, | ||
| 30 | + (error) => { | ||
| 31 | + console.error('API请求错误:', error) | ||
| 32 | + return Promise.reject(error) | ||
| 33 | + } | ||
| 34 | +) | ||
| 35 | + | ||
| 36 | +export interface DictType { | ||
| 37 | + dictTypeId: number | ||
| 38 | + dictType: string | ||
| 39 | + dictName: string | ||
| 40 | + status: number | ||
| 41 | + statusText: string | ||
| 42 | + remark?: string | ||
| 43 | + createBy?: string | ||
| 44 | + createTime: string | ||
| 45 | + updateBy?: string | ||
| 46 | + updateTime: string | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +export interface DictItem { | ||
| 50 | + dictItemId: number | ||
| 51 | + dictTypeId: number | ||
| 52 | + dictType: string | ||
| 53 | + dictLabel: string | ||
| 54 | + dictValue: string | ||
| 55 | + sort: number | ||
| 56 | + remark?: string | ||
| 57 | + createBy?: string | ||
| 58 | + createTime: string | ||
| 59 | + updateBy?: string | ||
| 60 | + updateTime: string | ||
| 61 | +} | ||
| 62 | + | ||
| 63 | +export interface DictTypeSearchParams { | ||
| 64 | + dictType?: string | ||
| 65 | + dictName?: string | ||
| 66 | + status?: number | ||
| 67 | + pageNum?: number | ||
| 68 | + pageSize?: number | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +export interface DictItemSearchParams { | ||
| 72 | + dictTypeId?: number | ||
| 73 | + dictLabel?: string | ||
| 74 | + dictValue?: string | ||
| 75 | + pageNum?: number | ||
| 76 | + pageSize?: number | ||
| 77 | +} | ||
| 78 | + | ||
| 79 | +export interface DictTypeAddReq { | ||
| 80 | + dictType: string | ||
| 81 | + dictName: string | ||
| 82 | + status: number | ||
| 83 | + remark?: string | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +export interface DictTypeUpdateReq extends DictTypeAddReq { | ||
| 87 | + dictTypeId: number | ||
| 88 | +} | ||
| 89 | + | ||
| 90 | +export interface DictItemAddReq { | ||
| 91 | + dictTypeId: number | ||
| 92 | + dictLabel: string | ||
| 93 | + dictValue: string | ||
| 94 | + sort?: number | ||
| 95 | + remark?: string | ||
| 10 | } | 96 | } |
| 11 | 97 | ||
| 12 | -// 获取所有字典项 | 98 | +export interface DictItemUpdateReq extends DictItemAddReq { |
| 13 | -export const getAllDictItems = () => { | 99 | + dictItemId: number |
| 14 | - return request.get('/api/dict/all') | ||
| 15 | } | 100 | } |
| 16 | 101 | ||
| 17 | -// 刷新字典缓存 | 102 | +export interface ApiResponse<T = any> { |
| 18 | -export const refreshDictCache = () => { | 103 | + code: number |
| 19 | - return request.post('/api/dict/refresh') | 104 | + message: string |
| 105 | + data: T | ||
| 106 | +} | ||
| 107 | + | ||
| 108 | +export interface PageResponse<T> { | ||
| 109 | + records: T[] | ||
| 110 | + total: number | ||
| 111 | + size: number | ||
| 112 | + current: number | ||
| 113 | + orders: any[] | ||
| 114 | + optimizeCountSql: boolean | ||
| 115 | + searchCount: boolean | ||
| 116 | + maxLimit: any | ||
| 117 | + countId: any | ||
| 118 | + pages: number | ||
| 119 | +} | ||
| 120 | + | ||
| 121 | +export const dictApi = { | ||
| 122 | + // 字典类型管理 | ||
| 123 | + // 获取字典类型列表 | ||
| 124 | + getDictTypes: (params: DictTypeSearchParams): Promise<ApiResponse<PageResponse<DictType>>> => { | ||
| 125 | + return api.get('/api/system/dict/type/list', { params }) | ||
| 126 | + }, | ||
| 127 | + | ||
| 128 | + // 获取字典类型详情 | ||
| 129 | + getDictTypeById: (dictTypeId: number): Promise<ApiResponse<DictType>> => { | ||
| 130 | + return api.get(`/api/system/dict/type/${dictTypeId}`) | ||
| 131 | + }, | ||
| 132 | + | ||
| 133 | + // 新增字典类型 | ||
| 134 | + createDictType: (dictTypeData: DictTypeAddReq): Promise<ApiResponse<any>> => { | ||
| 135 | + return api.post('/api/system/dict/type', dictTypeData) | ||
| 136 | + }, | ||
| 137 | + | ||
| 138 | + // 修改字典类型 | ||
| 139 | + updateDictType: (dictTypeData: DictTypeUpdateReq): Promise<ApiResponse<any>> => { | ||
| 140 | + return api.put('/api/system/dict/type', dictTypeData) | ||
| 141 | + }, | ||
| 142 | + | ||
| 143 | + // 删除字典类型 | ||
| 144 | + deleteDictTypes: (dictTypeIds: number[]): Promise<ApiResponse<any>> => { | ||
| 145 | + return api.delete(`/api/system/dict/type/${dictTypeIds.join(',')}`) | ||
| 146 | + }, | ||
| 147 | + | ||
| 148 | + // 获取字典类型选择框列表 | ||
| 149 | + getDictTypeOptions: (): Promise<ApiResponse<DictType[]>> => { | ||
| 150 | + return api.get('/api/system/dict/type/optionselect') | ||
| 151 | + }, | ||
| 152 | + | ||
| 153 | + // 刷新字典缓存 | ||
| 154 | + refreshDictCache: (): Promise<ApiResponse<any>> => { | ||
| 155 | + return api.delete('/api/system/dict/type/refreshCache') | ||
| 156 | + }, | ||
| 157 | + | ||
| 158 | + // 字典项管理 | ||
| 159 | + // 获取字典项列表 | ||
| 160 | + getDictItems: (params: DictItemSearchParams): Promise<ApiResponse<PageResponse<DictItem>>> => { | ||
| 161 | + return api.get('/api/system/dict/item/list', { params }) | ||
| 162 | + }, | ||
| 163 | + | ||
| 164 | + // 根据字典类型获取字典项列表 | ||
| 165 | + getDictItemsByType: (dictType: string): Promise<ApiResponse<DictItem[]>> => { | ||
| 166 | + return api.get(`/api/system/dict/item/type/${dictType}`) | ||
| 167 | + }, | ||
| 168 | + | ||
| 169 | + // 获取字典项详情 | ||
| 170 | + getDictItemById: (dictItemId: number): Promise<ApiResponse<DictItem>> => { | ||
| 171 | + return api.get(`/api/system/dict/item/${dictItemId}`) | ||
| 172 | + }, | ||
| 173 | + | ||
| 174 | + // 新增字典项 | ||
| 175 | + createDictItem: (dictItemData: DictItemAddReq): Promise<ApiResponse<any>> => { | ||
| 176 | + return api.post('/api/system/dict/item', dictItemData) | ||
| 177 | + }, | ||
| 178 | + | ||
| 179 | + // 修改字典项 | ||
| 180 | + updateDictItem: (dictItemData: DictItemUpdateReq): Promise<ApiResponse<any>> => { | ||
| 181 | + return api.put('/api/system/dict/item', dictItemData) | ||
| 182 | + }, | ||
| 183 | + | ||
| 184 | + // 删除字典项 | ||
| 185 | + deleteDictItems: (dictItemIds: number[]): Promise<ApiResponse<any>> => { | ||
| 186 | + return api.delete(`/api/system/dict/item/${dictItemIds.join(',')}`) | ||
| 187 | + }, | ||
| 20 | } | 188 | } |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -84,10 +84,11 @@ | ... | @@ -84,10 +84,11 @@ |
| 84 | <th>统一社会信用代码</th> | 84 | <th>统一社会信用代码</th> |
| 85 | <th>经销商等级</th> | 85 | <th>经销商等级</th> |
| 86 | <th>所在区域</th> | 86 | <th>所在区域</th> |
| 87 | - <th>联系人</th> | ||
| 88 | - <th>联系电话</th> | ||
| 89 | <th>合作起始日期</th> | 87 | <th>合作起始日期</th> |
| 90 | <th>合作状态</th> | 88 | <th>合作状态</th> |
| 89 | + <th>累计应返金额</th> | ||
| 90 | + <th>累计已返金额</th> | ||
| 91 | + <th>待返利总金额</th> | ||
| 91 | <th>操作</th> | 92 | <th>操作</th> |
| 92 | </tr> | 93 | </tr> |
| 93 | </thead> | 94 | </thead> |
| ... | @@ -105,14 +106,15 @@ | ... | @@ -105,14 +106,15 @@ |
| 105 | <td>{{ dealer.creditCode }}</td> | 106 | <td>{{ dealer.creditCode }}</td> |
| 106 | <td>{{ getDealerLevelText(dealer.dealerLevel) }}</td> | 107 | <td>{{ getDealerLevelText(dealer.dealerLevel) }}</td> |
| 107 | <td>{{ dealer.region }}</td> | 108 | <td>{{ dealer.region }}</td> |
| 108 | - <td>{{ dealer.contactPerson }}</td> | ||
| 109 | - <td>{{ dealer.contactPhone }}</td> | ||
| 110 | <td>{{ dealer.cooperateStartDate }}</td> | 109 | <td>{{ dealer.cooperateStartDate }}</td> |
| 111 | <td> | 110 | <td> |
| 112 | <span :class="getCooperateStatusClass(dealer.cooperateStatus)"> | 111 | <span :class="getCooperateStatusClass(dealer.cooperateStatus)"> |
| 113 | {{ getCooperateStatusText(dealer.cooperateStatus) }} | 112 | {{ getCooperateStatusText(dealer.cooperateStatus) }} |
| 114 | </span> | 113 | </span> |
| 115 | </td> | 114 | </td> |
| 115 | + <td class="amount-cell">{{ formatAmount(dealer.totalRebateAmount) }}</td> | ||
| 116 | + <td class="amount-cell">{{ formatAmount(dealer.usedRebateAmount) }}</td> | ||
| 117 | + <td class="amount-cell">{{ formatAmount(dealer.pendingRebateAmount) }}</td> | ||
| 116 | <td> | 118 | <td> |
| 117 | <button @click="handleEdit(dealer)" class="table-btn edit">✏️ 编辑</button> | 119 | <button @click="handleEdit(dealer)" class="table-btn edit">✏️ 编辑</button> |
| 118 | <button @click="handleDelete(dealer)" class="table-btn delete">🗑️ 删除</button> | 120 | <button @click="handleDelete(dealer)" class="table-btn delete">🗑️ 删除</button> |
| ... | @@ -445,6 +447,14 @@ const getCooperateStatusClass = (status: number) => { | ... | @@ -445,6 +447,14 @@ const getCooperateStatusClass = (status: number) => { |
| 445 | return classMap[status] || '' | 447 | return classMap[status] || '' |
| 446 | } | 448 | } |
| 447 | 449 | ||
| 450 | +// 格式化金额显示 | ||
| 451 | +const formatAmount = (amount: number | undefined) => { | ||
| 452 | + if (amount === undefined || amount === null) { | ||
| 453 | + return '¥0.00' | ||
| 454 | + } | ||
| 455 | + return `¥${amount.toFixed(2)}` | ||
| 456 | +} | ||
| 457 | + | ||
| 448 | 458 | ||
| 449 | // 获取分页页码数组 | 459 | // 获取分页页码数组 |
| 450 | const getPageNumbers = () => { | 460 | const getPageNumbers = () => { |
| ... | @@ -1283,4 +1293,12 @@ onMounted(() => { | ... | @@ -1283,4 +1293,12 @@ onMounted(() => { |
| 1283 | color: #67c23a; | 1293 | color: #67c23a; |
| 1284 | font-weight: 500; | 1294 | font-weight: 500; |
| 1285 | } | 1295 | } |
| 1296 | + | ||
| 1297 | +/* 金额单元格样式 */ | ||
| 1298 | +.amount-cell { | ||
| 1299 | + text-align: right; | ||
| 1300 | + font-weight: 500; | ||
| 1301 | + color: #1890ff; | ||
| 1302 | + font-family: 'Courier New', monospace; | ||
| 1303 | +} | ||
| 1286 | </style> | 1304 | </style> |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment