Compare commits
2 Commits
iteration/
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8229ad9248 | ||
|
|
fc01fa2ac9 |
@@ -10,6 +10,19 @@ export enum RefundStatus {
|
|||||||
RETURNED = 4 // 已退回
|
RETURNED = 4 // 已退回
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 审批状态
|
||||||
|
export enum RefundApprovalStatus {
|
||||||
|
SUBMITTING = 0, // 提交中
|
||||||
|
APPROVING = 1, // 审批中
|
||||||
|
APPROVED = 2, // 已通过
|
||||||
|
REJECTED = 3, // 已拒绝
|
||||||
|
REVOKED = 4, // 已撤销
|
||||||
|
REVOKED_AFTER_APPROVED = 5, // 通过后撤销
|
||||||
|
DELETED = 6, // 已删除
|
||||||
|
SUBMIT_FAILED = 7, // 提交失败
|
||||||
|
RESULT_UNKNOWN = 8 // 提交结果未知
|
||||||
|
}
|
||||||
|
|
||||||
export interface RefundAttachment {
|
export interface RefundAttachment {
|
||||||
file_key: string
|
file_key: string
|
||||||
file_name?: string
|
file_name?: string
|
||||||
@@ -70,7 +83,7 @@ export interface Refund {
|
|||||||
approval_provider?: 'wecom' | null
|
approval_provider?: 'wecom' | null
|
||||||
approval_instance_id?: number | null
|
approval_instance_id?: number | null
|
||||||
approval_source?: 'none' | 'legacy' | 'wecom' | null // 审批来源
|
approval_source?: 'none' | 'legacy' | 'wecom' | null // 审批来源
|
||||||
approval_status?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | null // 审批状态
|
approval_status?: RefundApprovalStatus | null // 审批状态
|
||||||
approval_status_name?: string | null // 审批状态名称
|
approval_status_name?: string | null // 审批状态名称
|
||||||
current_approver_summary?: string | null // 当前审批人摘要
|
current_approver_summary?: string | null // 当前审批人摘要
|
||||||
processing_status?: string | null // 业务处理状态
|
processing_status?: string | null // 业务处理状态
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { normalizeApiError } from '@/utils/business/apiError'
|
|||||||
import { syncCompatibleIdFields } from '@/utils/business/id'
|
import { syncCompatibleIdFields } from '@/utils/business/id'
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
timeout: 15000, // 请求超时时间(毫秒)
|
timeout: 90000, // 请求超时时间(毫秒)
|
||||||
baseURL: import.meta.env.DEV ? '' : import.meta.env.VITE_API_URL, // 开发服务器使用代理,其他模式使用完整URL
|
baseURL: import.meta.env.DEV ? '' : import.meta.env.VITE_API_URL, // 开发服务器使用代理,其他模式使用完整URL
|
||||||
withCredentials: false, // 异步请求携带cookie
|
withCredentials: false, // 异步请求携带cookie
|
||||||
transformRequest: [
|
transformRequest: [
|
||||||
|
|||||||
@@ -108,6 +108,7 @@
|
|||||||
v-model="allocateForm.target_shop_id"
|
v-model="allocateForm.target_shop_id"
|
||||||
:options="shopCascadeOptions"
|
:options="shopCascadeOptions"
|
||||||
:props="shopCascadeProps"
|
:props="shopCascadeProps"
|
||||||
|
:before-filter="handleAllocateShopBeforeFilter"
|
||||||
placeholder="请选择目标店铺"
|
placeholder="请选择目标店铺"
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
@@ -1049,6 +1050,62 @@
|
|||||||
const batchRealnamePolicyError = ref('')
|
const batchRealnamePolicyError = ref('')
|
||||||
const exportDialogVisible = ref(false)
|
const exportDialogVisible = ref(false)
|
||||||
const shopCascadeOptions = ref<any[]>([])
|
const shopCascadeOptions = ref<any[]>([])
|
||||||
|
let allocateShopSearchRequestId = 0
|
||||||
|
const mapShopCascadeNodes = (items: any[]) => {
|
||||||
|
const seen = new Set<number>()
|
||||||
|
|
||||||
|
return items.reduce<any[]>((nodes, item) => {
|
||||||
|
if (seen.has(item.id)) return nodes
|
||||||
|
|
||||||
|
seen.add(item.id)
|
||||||
|
nodes.push({
|
||||||
|
value: item.id,
|
||||||
|
label: item.shop_name,
|
||||||
|
leaf: !item.has_children
|
||||||
|
})
|
||||||
|
return nodes
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
const handleAllocateShopBeforeFilter = async (query: string) => {
|
||||||
|
const keyword = query.trim()
|
||||||
|
if (!keyword) return true
|
||||||
|
|
||||||
|
const requestId = ++allocateShopSearchRequestId
|
||||||
|
try {
|
||||||
|
const shopResponse = await ShopService.getShops({
|
||||||
|
page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
shop_name: keyword
|
||||||
|
})
|
||||||
|
if (requestId !== allocateShopSearchRequestId) return false
|
||||||
|
if (shopResponse.code !== 0) {
|
||||||
|
shopCascadeOptions.value = []
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentIds = Array.from(
|
||||||
|
new Set((shopResponse.data.items || []).map((shop) => shop.parent_id ?? null))
|
||||||
|
)
|
||||||
|
const cascadeResponses = await Promise.all(
|
||||||
|
parentIds.map((parentId) =>
|
||||||
|
ShopService.getShopsCascade({
|
||||||
|
shop_name: keyword,
|
||||||
|
parent_id: parentId ?? undefined
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (requestId !== allocateShopSearchRequestId) return false
|
||||||
|
|
||||||
|
shopCascadeOptions.value = mapShopCascadeNodes(
|
||||||
|
cascadeResponses.flatMap((response) => (response.code === 0 ? response.data || [] : []))
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
if (requestId === allocateShopSearchRequestId) shopCascadeOptions.value = []
|
||||||
|
console.error('搜索批量分配目标店铺失败:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
const shopCascadeProps = {
|
const shopCascadeProps = {
|
||||||
lazy: true,
|
lazy: true,
|
||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
@@ -1059,12 +1116,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShopsCascade({ parent_id: parentId })
|
const res = await ShopService.getShopsCascade({ parent_id: parentId })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
const nodes = (res.data || []).map((item: any) => ({
|
resolve(mapShopCascadeNodes(res.data || []))
|
||||||
value: item.id,
|
|
||||||
label: item.shop_name,
|
|
||||||
leaf: !item.has_children
|
|
||||||
}))
|
|
||||||
resolve(nodes)
|
|
||||||
} else {
|
} else {
|
||||||
resolve([])
|
resolve([])
|
||||||
}
|
}
|
||||||
@@ -1081,11 +1133,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShopsCascade({ parent_id: undefined })
|
const res = await ShopService.getShopsCascade({ parent_id: undefined })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
shopCascadeOptions.value = (res.data || []).map((item: any) => ({
|
shopCascadeOptions.value = mapShopCascadeNodes(res.data || [])
|
||||||
value: item.id,
|
|
||||||
label: item.shop_name,
|
|
||||||
leaf: !item.has_children
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载顶级店铺失败:', error)
|
console.error('加载顶级店铺失败:', error)
|
||||||
@@ -2527,10 +2575,7 @@
|
|||||||
|
|
||||||
const showEnterpriseDeviceAuthorizeDialog = async () => {
|
const showEnterpriseDeviceAuthorizeDialog = async () => {
|
||||||
resetEnterpriseDeviceAuthorizeForm()
|
resetEnterpriseDeviceAuthorizeForm()
|
||||||
await Promise.all([
|
await Promise.all([handleSearchEnterprise(), loadTopLevelShopCascadeOptions()])
|
||||||
handleSearchEnterprise(),
|
|
||||||
loadTopLevelShopCascadeOptions()
|
|
||||||
])
|
|
||||||
enterpriseDeviceAuthorizeDialogVisible.value = true
|
enterpriseDeviceAuthorizeDialogVisible.value = true
|
||||||
enterpriseDeviceAuthorizeFormRef.value?.clearValidate()
|
enterpriseDeviceAuthorizeFormRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -268,8 +268,8 @@
|
|||||||
{{ createNewDeviceEmptyMessage }}
|
{{ createNewDeviceEmptyMessage }}
|
||||||
</div>
|
</div>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem v-if="createDirectInheritedShopHint" label="归属提示">
|
<ElFormItem label="归属提示">
|
||||||
<div class="exchange-shop-hint">{{ createDirectInheritedShopHint }}</div>
|
<div class="exchange-shop-hint">新资产会继承旧资产店铺</div>
|
||||||
</ElFormItem>
|
</ElFormItem>
|
||||||
<ElFormItem v-if="createForm.flow_type === 'direct'" label="是否迁移数据">
|
<ElFormItem v-if="createForm.flow_type === 'direct'" label="是否迁移数据">
|
||||||
<ElSwitch v-model="createForm.migrate_data" />
|
<ElSwitch v-model="createForm.migrate_data" />
|
||||||
@@ -771,11 +771,6 @@
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const createDirectInheritedShopHint = computed(() => {
|
|
||||||
const shopName = getShopDisplayName(createSelectedNewAsset.value)
|
|
||||||
return shopName ? `换货完成后将归属:${shopName}` : ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const shipInheritedShopDisplayText = computed(() => {
|
const shipInheritedShopDisplayText = computed(() => {
|
||||||
const shopName = getShopDisplayName(shipSelectedNewAsset.value)
|
const shopName = getShopDisplayName(shipSelectedNewAsset.value)
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,7 @@
|
|||||||
v-model="allocateForm.to_shop_id"
|
v-model="allocateForm.to_shop_id"
|
||||||
:options="shopCascadeOptions"
|
:options="shopCascadeOptions"
|
||||||
:props="shopCascadeProps"
|
:props="shopCascadeProps"
|
||||||
|
:before-filter="handleAllocateShopBeforeFilter"
|
||||||
placeholder="请选择目标店铺"
|
placeholder="请选择目标店铺"
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
@@ -1523,6 +1524,62 @@
|
|||||||
|
|
||||||
// 店铺相关
|
// 店铺相关
|
||||||
const shopCascadeOptions = ref<any[]>([])
|
const shopCascadeOptions = ref<any[]>([])
|
||||||
|
let allocateShopSearchRequestId = 0
|
||||||
|
const mapShopCascadeNodes = (items: any[]) => {
|
||||||
|
const seen = new Set<number>()
|
||||||
|
|
||||||
|
return items.reduce<any[]>((nodes, item) => {
|
||||||
|
if (seen.has(item.id)) return nodes
|
||||||
|
|
||||||
|
seen.add(item.id)
|
||||||
|
nodes.push({
|
||||||
|
value: item.id,
|
||||||
|
label: item.shop_name,
|
||||||
|
leaf: !item.has_children
|
||||||
|
})
|
||||||
|
return nodes
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
const handleAllocateShopBeforeFilter = async (query: string) => {
|
||||||
|
const keyword = query.trim()
|
||||||
|
if (!keyword) return true
|
||||||
|
|
||||||
|
const requestId = ++allocateShopSearchRequestId
|
||||||
|
try {
|
||||||
|
const shopResponse = await ShopService.getShops({
|
||||||
|
page: 1,
|
||||||
|
page_size: 20,
|
||||||
|
shop_name: keyword
|
||||||
|
})
|
||||||
|
if (requestId !== allocateShopSearchRequestId) return false
|
||||||
|
if (shopResponse.code !== 0) {
|
||||||
|
shopCascadeOptions.value = []
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentIds = Array.from(
|
||||||
|
new Set((shopResponse.data.items || []).map((shop) => shop.parent_id ?? null))
|
||||||
|
)
|
||||||
|
const cascadeResponses = await Promise.all(
|
||||||
|
parentIds.map((parentId) =>
|
||||||
|
ShopService.getShopsCascade({
|
||||||
|
shop_name: keyword,
|
||||||
|
parent_id: parentId ?? undefined
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (requestId !== allocateShopSearchRequestId) return false
|
||||||
|
|
||||||
|
shopCascadeOptions.value = mapShopCascadeNodes(
|
||||||
|
cascadeResponses.flatMap((response) => (response.code === 0 ? response.data || [] : []))
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
} catch (error) {
|
||||||
|
if (requestId === allocateShopSearchRequestId) shopCascadeOptions.value = []
|
||||||
|
console.error('搜索批量分配目标店铺失败:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
const shopCascadeProps = {
|
const shopCascadeProps = {
|
||||||
lazy: true,
|
lazy: true,
|
||||||
checkStrictly: true,
|
checkStrictly: true,
|
||||||
@@ -1533,12 +1590,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShopsCascade({ parent_id: parentId })
|
const res = await ShopService.getShopsCascade({ parent_id: parentId })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
const nodes = (res.data || []).map((item: any) => ({
|
resolve(mapShopCascadeNodes(res.data || []))
|
||||||
value: item.id,
|
|
||||||
label: item.shop_name,
|
|
||||||
leaf: !item.has_children
|
|
||||||
}))
|
|
||||||
resolve(nodes)
|
|
||||||
} else {
|
} else {
|
||||||
resolve([])
|
resolve([])
|
||||||
}
|
}
|
||||||
@@ -1555,11 +1607,7 @@
|
|||||||
try {
|
try {
|
||||||
const res = await ShopService.getShopsCascade({ parent_id: undefined })
|
const res = await ShopService.getShopsCascade({ parent_id: undefined })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
shopCascadeOptions.value = (res.data || []).map((item: any) => ({
|
shopCascadeOptions.value = mapShopCascadeNodes(res.data || [])
|
||||||
value: item.id,
|
|
||||||
label: item.shop_name,
|
|
||||||
leaf: !item.has_children
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载顶级店铺失败:', error)
|
console.error('加载顶级店铺失败:', error)
|
||||||
@@ -2486,6 +2534,7 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
allocateDialogVisible.value = true
|
allocateDialogVisible.value = true
|
||||||
|
shopCascadeOptions.value = []
|
||||||
Object.assign(allocateForm, {
|
Object.assign(allocateForm, {
|
||||||
selection_type: CardSelectionType.LIST,
|
selection_type: CardSelectionType.LIST,
|
||||||
to_shop_id: undefined,
|
to_shop_id: undefined,
|
||||||
@@ -2700,10 +2749,7 @@
|
|||||||
|
|
||||||
const showEnterpriseCardRecallDialog = async () => {
|
const showEnterpriseCardRecallDialog = async () => {
|
||||||
resetEnterpriseCardRecallForm()
|
resetEnterpriseCardRecallForm()
|
||||||
await Promise.all([
|
await Promise.all([handleSearchEnterprise(), loadAllocateCarrierOptions()])
|
||||||
handleSearchEnterprise(),
|
|
||||||
loadAllocateCarrierOptions()
|
|
||||||
])
|
|
||||||
enterpriseCardRecallDialogVisible.value = true
|
enterpriseCardRecallDialogVisible.value = true
|
||||||
enterpriseCardRecallFormRef.value?.clearValidate()
|
enterpriseCardRecallFormRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
@@ -2823,10 +2869,7 @@
|
|||||||
selection_type:
|
selection_type:
|
||||||
selectedCards.value.length > 0 ? CardSelectionType.LIST : CardSelectionType.FILTER
|
selectedCards.value.length > 0 ? CardSelectionType.LIST : CardSelectionType.FILTER
|
||||||
})
|
})
|
||||||
await Promise.all([
|
await Promise.all([loadPackageSeriesList(), loadAllocateCarrierOptions()])
|
||||||
loadPackageSeriesList(),
|
|
||||||
loadAllocateCarrierOptions()
|
|
||||||
])
|
|
||||||
seriesBindingDialogVisible.value = true
|
seriesBindingDialogVisible.value = true
|
||||||
seriesBindingFormRef.value?.clearValidate()
|
seriesBindingFormRef.value?.clearValidate()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,13 @@
|
|||||||
import DetailPage from '@/components/common/DetailPage.vue'
|
import DetailPage from '@/components/common/DetailPage.vue'
|
||||||
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
import type { DetailSection } from '@/components/common/DetailPage.vue'
|
||||||
import { RefundService } from '@/api/modules'
|
import { RefundService } from '@/api/modules'
|
||||||
import type { Refund, ResubmitRefundRequest, RefundAttachment } from '@/types/api'
|
import {
|
||||||
|
RefundApprovalStatus,
|
||||||
|
RefundStatus,
|
||||||
|
type Refund,
|
||||||
|
type ResubmitRefundRequest,
|
||||||
|
type RefundAttachment
|
||||||
|
} from '@/types/api'
|
||||||
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
|
import { fenToYuan, formatDateTime, yuanToFen } from '@/utils/business/format'
|
||||||
import { toVoucherKeyList, getErrorMessage } from '@/utils/business'
|
import { toVoucherKeyList, getErrorMessage } from '@/utils/business'
|
||||||
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
|
import PaymentVoucherDialog from '@/components/business/PaymentVoucherDialog.vue'
|
||||||
@@ -456,22 +462,14 @@
|
|||||||
resubmitUploadRef.value?.clearFiles(false)
|
resubmitUploadRef.value?.clearFiles(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const canResubmit = (item: Refund) => {
|
const canResubmit = (item: Refund) =>
|
||||||
const statusText = [item.approval_status, item.approval_status_name, item.status_name]
|
item.status === RefundStatus.REJECTED ||
|
||||||
.filter(Boolean)
|
item.status === RefundStatus.RETURNED ||
|
||||||
.join(' ')
|
item.approval_status === RefundApprovalStatus.REJECTED ||
|
||||||
.toLowerCase()
|
item.approval_status === RefundApprovalStatus.REVOKED ||
|
||||||
|
item.approval_status === RefundApprovalStatus.REVOKED_AFTER_APPROVED ||
|
||||||
return (
|
item.approval_status === RefundApprovalStatus.SUBMIT_FAILED ||
|
||||||
item.status === 3 ||
|
item.approval_status === RefundApprovalStatus.RESULT_UNKNOWN
|
||||||
statusText.includes('reject') ||
|
|
||||||
statusText.includes('revoke') ||
|
|
||||||
statusText.includes('delete') ||
|
|
||||||
statusText.includes('驳回') ||
|
|
||||||
statusText.includes('撤销') ||
|
|
||||||
statusText.includes('删除')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleShowResubmit = () => {
|
const handleShowResubmit = () => {
|
||||||
if (!refund.value || !canResubmit(refund.value)) return
|
if (!refund.value || !canResubmit(refund.value)) return
|
||||||
|
|||||||
@@ -150,6 +150,7 @@
|
|||||||
import type { FormInstance, FormRules } from 'element-plus'
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
import {
|
import {
|
||||||
RefundStatus,
|
RefundStatus,
|
||||||
|
RefundApprovalStatus,
|
||||||
type Refund,
|
type Refund,
|
||||||
type RefundQueryParams,
|
type RefundQueryParams,
|
||||||
type ResubmitRefundRequest,
|
type ResubmitRefundRequest,
|
||||||
@@ -734,22 +735,14 @@
|
|||||||
return keys.length ? keys : toVoucherKeyList(row.refund_voucher_key)
|
return keys.length ? keys : toVoucherKeyList(row.refund_voucher_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
const canResubmit = (row: Refund) => {
|
const canResubmit = (row: Refund) =>
|
||||||
const statusText = [row.approval_status, row.approval_status_name, row.status_name]
|
row.status === RefundStatus.REJECTED ||
|
||||||
.filter(Boolean)
|
row.status === RefundStatus.RETURNED ||
|
||||||
.join(' ')
|
row.approval_status === RefundApprovalStatus.REJECTED ||
|
||||||
.toLowerCase()
|
row.approval_status === RefundApprovalStatus.REVOKED ||
|
||||||
|
row.approval_status === RefundApprovalStatus.REVOKED_AFTER_APPROVED ||
|
||||||
return (
|
row.approval_status === RefundApprovalStatus.SUBMIT_FAILED ||
|
||||||
row.status === 3 ||
|
row.approval_status === RefundApprovalStatus.RESULT_UNKNOWN
|
||||||
statusText.includes('reject') ||
|
|
||||||
statusText.includes('revoke') ||
|
|
||||||
statusText.includes('delete') ||
|
|
||||||
statusText.includes('驳回') ||
|
|
||||||
statusText.includes('撤销') ||
|
|
||||||
statusText.includes('删除')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const canTriggerApproval = (row: Refund) => {
|
const canTriggerApproval = (row: Refund) => {
|
||||||
const approvalStatusEmpty = row.approval_status === undefined || row.approval_status === null
|
const approvalStatusEmpty = row.approval_status === undefined || row.approval_status === null
|
||||||
|
|||||||
Reference in New Issue
Block a user