feat(approval): 添加审批中心功能,包括审批列表和提交审批
新增审批中心页面,支持管理员查看审批列表,包含搜索、分页和状态筛选功能。同时优化了提交审批页面,增加退货备注字段,并改进上传文件后的反馈提示。
This commit is contained in:
parent
42eae0b1cd
commit
9c81c228ee
|
@ -1,5 +1,13 @@
|
|||
import { request } from '@/http/axios'
|
||||
import { SubmitApprovalRequestData, SubmitApprovalResponseData } from './type'
|
||||
import { SubmitApprovalRequestData, SubmitApprovalResponseData, SearchApiReturnApprovalQuery, ApiResponsePageData, ReturnApprovalEntity } from './type'
|
||||
|
||||
export const getApprovalListApi = (params: SearchApiReturnApprovalQuery) => {
|
||||
return request<ApiResponsePageData<ReturnApprovalEntity>>({
|
||||
url: 'approval/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export const submitApprovalApi = (data: SubmitApprovalRequestData) => {
|
||||
return request<SubmitApprovalResponseData>({
|
||||
|
|
|
@ -2,6 +2,55 @@ export interface SubmitApprovalRequestData {
|
|||
orderGoodsId: number
|
||||
returnQuantity: number
|
||||
returnImages: string
|
||||
returnRemark: string
|
||||
}
|
||||
|
||||
export interface SearchApiReturnApprovalQuery {
|
||||
pageNum: number
|
||||
pageSize: number
|
||||
approvalId?: number
|
||||
orderId?: number
|
||||
goodsId?: number
|
||||
status?: number
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
}
|
||||
|
||||
export interface ApiResponsePageData<T> {
|
||||
code: number
|
||||
msg: string
|
||||
data: {
|
||||
total: number
|
||||
rows: T[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ReturnApprovalEntity {
|
||||
approvalId: number
|
||||
orderId: number
|
||||
goodsId: number
|
||||
/** 关联订单商品ID */
|
||||
orderGoodsId: number
|
||||
/** 归还数量 */
|
||||
returnQuantity: number
|
||||
/** 商品单价 */
|
||||
goodsPrice: number
|
||||
status: number
|
||||
returnAmount: number
|
||||
/** 归还图片路径数组 */
|
||||
returnImages: string
|
||||
/** 审核图片路径数组 */
|
||||
auditImages: string
|
||||
/** 归还说明 */
|
||||
returnRemark: string
|
||||
/** 审核说明 */
|
||||
auditRemark: string
|
||||
createTime: string
|
||||
updateTime: string
|
||||
/** 商品名称 */
|
||||
goodsName: string
|
||||
/** 封面图URL */
|
||||
coverImg: string
|
||||
}
|
||||
|
||||
export type SubmitApprovalResponseData = ApiResponseMsgData<{
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
<template>
|
||||
<div class="approval-list-container">
|
||||
<!-- 搜索表单 -->
|
||||
<van-form @submit="handleSearch">
|
||||
<van-field
|
||||
v-model="searchParams.approvalId"
|
||||
label="审批单号"
|
||||
type="number"
|
||||
placeholder="请输入审批单号"
|
||||
/>
|
||||
|
||||
<van-field
|
||||
v-model="searchParams.orderId"
|
||||
label="订单编号"
|
||||
type="number"
|
||||
placeholder="请输入订单编号"
|
||||
/>
|
||||
|
||||
<van-field
|
||||
v-model="searchParams.goodsId"
|
||||
label="商品ID"
|
||||
type="number"
|
||||
placeholder="请输入商品ID"
|
||||
/>
|
||||
|
||||
<van-field
|
||||
name="status"
|
||||
label="审批状态"
|
||||
readonly
|
||||
clickable
|
||||
:value="statusText"
|
||||
placeholder="请选择状态"
|
||||
@click="showStatusPicker = true"
|
||||
/>
|
||||
<van-popup v-model:show="showStatusPicker" position="bottom">
|
||||
<van-picker
|
||||
:columns="statusOptions"
|
||||
@confirm="onStatusConfirm"
|
||||
@cancel="showStatusPicker = false"
|
||||
/>
|
||||
</van-popup>
|
||||
|
||||
<!-- <van-field
|
||||
readonly
|
||||
clickable
|
||||
name="date"
|
||||
:value="dateRangeText"
|
||||
label="申请时间"
|
||||
placeholder="选择时间范围"
|
||||
@click="showDatePicker = true"
|
||||
/>
|
||||
<van-popup v-model:show="showDatePicker" position="bottom">
|
||||
<van-datetime-picker
|
||||
type="daterange"
|
||||
@confirm="onDateConfirm"
|
||||
@cancel="showDatePicker = false"
|
||||
/>
|
||||
</van-popup> -->
|
||||
|
||||
<div style="margin: 16px;">
|
||||
<van-button block type="primary" native-type="submit">搜索</van-button>
|
||||
<van-button
|
||||
block
|
||||
plain
|
||||
type="primary"
|
||||
style="margin-top: 10px;"
|
||||
@click="handleReset"
|
||||
>重置</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
|
||||
<!-- 审批列表 -->
|
||||
<van-list
|
||||
v-model:loading="loading"
|
||||
:finished="finished"
|
||||
finished-text="没有更多了"
|
||||
@load="onLoad"
|
||||
>
|
||||
<van-cell
|
||||
v-for="item in list"
|
||||
:key="item.approvalId"
|
||||
:title="`审批单号:${item.approvalId}`"
|
||||
>
|
||||
<template #label>
|
||||
<div>商品名称:{{ item.goodsName }}</div>
|
||||
<div>申请时间:{{ item.createTime }}</div>
|
||||
<van-tag :type="statusTagType(item.status)">
|
||||
{{ statusMap[item.status] }}
|
||||
</van-tag>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getApprovalListApi } from '@/common/apis/approval'
|
||||
import type { SearchApiReturnApprovalQuery, ReturnApprovalEntity } from '@/common/apis/approval/type'
|
||||
import type { PickerConfirmEventParams } from 'vant/es';
|
||||
|
||||
// 搜索参数
|
||||
const searchParams = reactive<SearchApiReturnApprovalQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
|
||||
// 状态选择相关
|
||||
const showStatusPicker = ref(false)
|
||||
const statusOptions = [
|
||||
{ text: '全部', value: undefined },
|
||||
{ text: '待审核', value: 0 },
|
||||
{ text: '已通过', value: 1 },
|
||||
{ text: '已拒绝', value: 2 },
|
||||
]
|
||||
|
||||
const statusMap: { [key: number]: string } = {
|
||||
0: '待审核',
|
||||
1: '已通过',
|
||||
2: '已拒绝'
|
||||
}
|
||||
|
||||
const statusText = ref('')
|
||||
|
||||
// 时间选择相关
|
||||
const showDatePicker = ref(false)
|
||||
const dateRangeText = ref('')
|
||||
|
||||
// 列表相关
|
||||
const list = ref<ReturnApprovalEntity[]>([])
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
|
||||
// 状态标签类型
|
||||
const statusTagType = (status: number) => {
|
||||
switch (status) {
|
||||
case 0: return 'warning'
|
||||
case 1: return 'success'
|
||||
case 2: return 'danger'
|
||||
default: return 'default'
|
||||
}
|
||||
}
|
||||
|
||||
// 处理状态选择
|
||||
const onStatusConfirm = (e: PickerConfirmEventParams) => {
|
||||
const { selectedOptions } = e;
|
||||
searchParams.status = Number(selectedOptions[0]?.value);
|
||||
showStatusPicker.value = false;
|
||||
// 确保赋值给 statusText 的是字符串类型
|
||||
statusText.value = String(selectedOptions[0]?.text || '');
|
||||
}
|
||||
|
||||
// 处理时间选择
|
||||
const onDateConfirm = (values: Date[]) => {
|
||||
const [start, end] = values
|
||||
searchParams.startTime = start.toISOString().split('T')[0]
|
||||
searchParams.endTime = end.toISOString().split('T')[0]
|
||||
dateRangeText.value = `${searchParams.startTime} 至 ${searchParams.endTime}`
|
||||
showDatePicker.value = false
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
list.value = []
|
||||
searchParams.pageNum = 1
|
||||
onLoad()
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(searchParams, {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
approvalId: undefined,
|
||||
orderId: undefined,
|
||||
goodsId: undefined,
|
||||
status: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
})
|
||||
statusText.value = ''
|
||||
dateRangeText.value = ''
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
// 加载数据
|
||||
const onLoad = async () => {
|
||||
try {
|
||||
const { data } = await getApprovalListApi(searchParams)
|
||||
list.value.push(...data.rows)
|
||||
loading.value = false
|
||||
|
||||
if (list.value.length >= data.total) {
|
||||
finished.value = true
|
||||
} else {
|
||||
searchParams.pageNum++
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取审批列表失败', error)
|
||||
finished.value = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.approval-list-container {
|
||||
padding: 12px;
|
||||
}
|
||||
.van-cell__title {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
.van-cell__label {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
|
@ -13,7 +13,8 @@ const route = useRoute()
|
|||
const formData = ref<SubmitApprovalRequestData>({
|
||||
orderGoodsId: Number(route.query.orderGoodsId),
|
||||
returnQuantity: 1,
|
||||
returnImages: ''
|
||||
returnImages: '',
|
||||
returnRemark: ''
|
||||
})
|
||||
|
||||
watch(() => route.query.orderGoodsId, (newVal) => {
|
||||
|
@ -71,10 +72,9 @@ const handleFileUpload = async (items: UploaderFileListItem | UploaderFileListIt
|
|||
const urls = await Promise.all(uploadPromises)
|
||||
files.forEach((item, index) => {
|
||||
item.status = 'done'
|
||||
item.message = ''
|
||||
item.message = '上传成功'
|
||||
item.url = urls[index].url
|
||||
})
|
||||
showToast('上传成功')
|
||||
} catch (error) {
|
||||
showConfirmDialog({
|
||||
title: '上传失败',
|
||||
|
@ -96,7 +96,13 @@ const handleSubmit = async () => {
|
|||
|
||||
if (code === 0) {
|
||||
showSuccessToast('提交成功')
|
||||
router.push('/order/' + orderId)
|
||||
try {
|
||||
await showConfirmDialog({
|
||||
title: "提交成功",
|
||||
message: `退货申请已提交,等待管理员审核`
|
||||
})
|
||||
} catch (error) { }
|
||||
router.push('/order/' + orderId.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
|
@ -118,6 +124,7 @@ const handleSubmit = async () => {
|
|||
<van-cell-group>
|
||||
<!-- 移除订单ID和商品ID的输入框 -->
|
||||
<van-field v-model="formData.returnQuantity" label="退还数量" type="number" :min="1" />
|
||||
<van-field v-model="formData.returnRemark" label="退货备注" type="textarea" rows="2" autosize />
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group class="upload-section">
|
||||
|
|
|
@ -75,6 +75,7 @@ const balance = computed(() => wxStore.balance)
|
|||
<van-cell-group>
|
||||
<van-cell title="订单列表" is-link @click="router.push('/order-list')" />
|
||||
<van-cell title="柜机管理" is-link @click="router.push('/cabinet')" v-if="wxStore.isCabinetAdmin"/>
|
||||
<van-cell title="审批中心" is-link @click="router.push('/approval/list')" v-if="wxStore.isCabinetAdmin"/>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -87,6 +87,25 @@ export const routes: RouteRecordRaw[] = [
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/approval/list',
|
||||
component: () => import('@/pages/approval/list.vue'),
|
||||
name: "Approval",
|
||||
meta: {
|
||||
title: '审批中心',
|
||||
keepAlive: true,
|
||||
layout: {
|
||||
navBar: {
|
||||
showNavBar: false,
|
||||
showLeftArrow: false
|
||||
},
|
||||
tabbar: {
|
||||
showTabbar: false,
|
||||
icon: "home-o"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/",
|
||||
component: () => import("@/pages/product/ProductList.vue"),
|
||||
|
|
|
@ -17,12 +17,16 @@ declare module 'vue' {
|
|||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||
VanDivider: typeof import('vant/es')['Divider']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanForm: typeof import('vant/es')['Form']
|
||||
VanGrid: typeof import('vant/es')['Grid']
|
||||
VanGridItem: typeof import('vant/es')['GridItem']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanImage: typeof import('vant/es')['Image']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanLoading: typeof import('vant/es')['Loading']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
VanPicker: typeof import('vant/es')['Picker']
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
VanRadio: typeof import('vant/es')['Radio']
|
||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||
VanSidebar: typeof import('vant/es')['Sidebar']
|
||||
|
|
Loading…
Reference in New Issue