|
|
@@ -133,6 +133,34 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
+ <view class="detail-info-card">
|
|
|
+ <view class="detail-info-card__title">关联发票</view>
|
|
|
+ <view v-if="linkedInvoices.length" class="invoice-thumb-grid" style="margin-top: 0">
|
|
|
+ <view
|
|
|
+ v-for="pick in linkedInvoices"
|
|
|
+ :key="pick.key"
|
|
|
+ class="invoice-thumb"
|
|
|
+ @click="previewInvoicePick(pick)"
|
|
|
+ >
|
|
|
+ <view class="invoice-thumb__media">
|
|
|
+ <image
|
|
|
+ v-if="isImageFileType(pick.fileType) && pick.previewUrl"
|
|
|
+ :src="pick.previewUrl"
|
|
|
+ mode="aspectFill"
|
|
|
+ />
|
|
|
+ <view v-else class="invoice-thumb__doc">
|
|
|
+ <text class="invoice-thumb__doc-ext">{{ fileExtLabel(pick.fileName) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="invoice-thumb__meta">
|
|
|
+ <text class="invoice-thumb__amt">¥{{ formatAmount(pick.amount) }}</text>
|
|
|
+ <text class="invoice-thumb__date">{{ formatInvoiceDateYmd(pick.createTime) }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view v-else class="detail-section-empty">暂无关联发票</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
<view class="detail-info-card">
|
|
|
<view class="detail-info-card__title">申请附件</view>
|
|
|
<view v-if="attachments.length" class="att-grid">
|
|
|
@@ -187,6 +215,7 @@
|
|
|
|
|
|
<view v-if="showActions" class="bottom-action-bar">
|
|
|
<template v-if="detail?.status === 'draft'">
|
|
|
+ <button class="btn btn-primary" style="flex: 1" @click="handleEdit">编辑</button>
|
|
|
<button
|
|
|
class="btn btn-primary"
|
|
|
style="flex: 1"
|
|
|
@@ -205,8 +234,14 @@
|
|
|
</button>
|
|
|
</template>
|
|
|
<template v-if="detail?.status === 'rejected'">
|
|
|
- <button class="btn btn-primary" style="flex: 1" @click="handleResubmit">
|
|
|
- 重新提交
|
|
|
+ <button class="btn btn-primary" style="flex: 1" @click="handleEdit">编辑</button>
|
|
|
+ <button
|
|
|
+ class="btn btn-primary"
|
|
|
+ style="flex: 1"
|
|
|
+ :disabled="actionLoading.submit"
|
|
|
+ @click="handleSubmit"
|
|
|
+ >
|
|
|
+ 提交审批
|
|
|
</button>
|
|
|
</template>
|
|
|
<template v-if="canWithdraw">
|
|
|
@@ -238,6 +273,11 @@ import {
|
|
|
flattenExpenseTree,
|
|
|
resolveExpenseDisplay
|
|
|
} from '@/utils/bxFormat'
|
|
|
+import {
|
|
|
+ isImageFileType,
|
|
|
+ fileExtLabel,
|
|
|
+ formatInvoiceDateYmd
|
|
|
+} from '@/utils/bxInvoiceThumb'
|
|
|
import { getSafeAreaStyle } from '@/utils/safeArea'
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
import { buildApplyAttachmentDisplayName } from '@/utils/bxAttachmentDisplayName'
|
|
|
@@ -250,6 +290,7 @@ const detail = ref(null)
|
|
|
const detailTab = ref(0)
|
|
|
const approvals = ref([])
|
|
|
const attachments = ref([])
|
|
|
+const linkedInvoices = ref([])
|
|
|
const flatList = ref([])
|
|
|
const actionLoading = reactive({ submit: false, delete: false, withdraw: false })
|
|
|
|
|
|
@@ -300,6 +341,26 @@ function previewAtt(file) {
|
|
|
uni.previewImage({ urls: [file.previewUrl], current: file.previewUrl })
|
|
|
}
|
|
|
|
|
|
+async function previewInvoicePick(pick) {
|
|
|
+ if (!isImageFileType(pick.fileType)) {
|
|
|
+ uni.showToast({ title: '非图片附件请在管理端查看', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ let url = pick.previewUrl
|
|
|
+ if (!url && pick.attachmentId) {
|
|
|
+ try {
|
|
|
+ const pRes = await attachmentApi.preview(pick.attachmentId)
|
|
|
+ url = pRes?.data?.url || ''
|
|
|
+ if (url) pick.previewUrl = url
|
|
|
+ } catch (e) {
|
|
|
+ uni.showToast({ title: '暂无法预览', icon: 'none' })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (url) uni.previewImage({ urls: [url], current: url })
|
|
|
+ else uni.showToast({ title: '暂无法预览', icon: 'none' })
|
|
|
+}
|
|
|
+
|
|
|
function attachmentDisplayName(file, index) {
|
|
|
return buildApplyAttachmentDisplayName({
|
|
|
remark: detail.value?.remark || '',
|
|
|
@@ -348,6 +409,38 @@ async function loadDetail() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ const invs = detail.value?.invoices || []
|
|
|
+ linkedInvoices.value = invs
|
|
|
+ .map((inv) => {
|
|
|
+ const attachmentId = String(inv.attachmentId || inv.attachment_id || '')
|
|
|
+ if (!attachmentId) return null
|
|
|
+ return {
|
|
|
+ key: `${inv.id || inv.invoiceId}:${attachmentId}`,
|
|
|
+ invoiceId: String(inv.id || inv.invoiceId || ''),
|
|
|
+ attachmentId,
|
|
|
+ amount: inv.amount,
|
|
|
+ createTime: inv.createTime || inv.create_time || '',
|
|
|
+ fileName: inv.fileName || inv.file_name || '发票附件',
|
|
|
+ fileType: inv.fileType || inv.file_type || '',
|
|
|
+ previewUrl: '',
|
|
|
+ previewLoading: false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .filter(Boolean)
|
|
|
+
|
|
|
+ for (const item of linkedInvoices.value) {
|
|
|
+ if (!isImageFileType(item.fileType)) continue
|
|
|
+ item.previewLoading = true
|
|
|
+ try {
|
|
|
+ const pRes = await attachmentApi.preview(item.attachmentId)
|
|
|
+ item.previewUrl = pRes?.data?.url || ''
|
|
|
+ } catch (e) {
|
|
|
+ // keep empty
|
|
|
+ } finally {
|
|
|
+ item.previewLoading = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
try {
|
|
|
const attRes = await attachmentApi.listByBiz('reimburse_apply', id)
|
|
|
const list = (attRes.data || []).map((a) => ({
|
|
|
@@ -410,7 +503,7 @@ function handleDelete() {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-function handleResubmit() {
|
|
|
+function handleEdit() {
|
|
|
if (!detail.value) return
|
|
|
uni.navigateTo({
|
|
|
url: `${PAGE_PATHS.bxReimburseApplyForm}?id=${detail.value.id}`
|