Просмотр исходного кода

feat(miniprogram): show remark-based names on reimburse apply attachments

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 1 месяц назад
Родитель
Сommit
a1ace0cf9a

+ 13 - 1
miniprogram/pages/bx/reimburse/apply.vue

@@ -167,9 +167,10 @@
           {{ uploading ? '上传中…' : '上传图片' }}
         </button>
         <view v-if="files.length" class="att-grid">
-          <view v-for="(file, idx) in files" :key="file.id" class="att-img">
+          <view v-for="(file, idx) in files" :key="file.id" class="att-img att-img--with-name">
             <image :src="file.previewUrl || file.localPath" mode="aspectFill" />
             <view v-if="!file._pending" class="del" @click.stop="removeFile(idx)">×</view>
+            <text class="att-img__name">{{ attachmentDisplayName(file, idx) }}</text>
           </view>
         </view>
         <view v-else class="detail-section-empty" style="margin-top: 8px">暂无附件(可选)</view>
@@ -264,6 +265,7 @@ import {
   formatExpenseName
 } from '@/utils/bxFormat'
 import { getSafeAreaStyle } from '@/utils/safeArea'
+import { buildApplyAttachmentDisplayName } from '@/utils/bxAttachmentDisplayName'
 
 const safeAreaStyle = getSafeAreaStyle()
 
@@ -339,6 +341,14 @@ function money(v) {
   })
 }
 
+function attachmentDisplayName(file, index) {
+  return buildApplyAttachmentDisplayName({
+    remark: form.remark || '',
+    originalFileName: file.fileName || '',
+    index1: index + 1
+  })
+}
+
 function lineExpenseDisplay(id) {
   if (id === '' || id == null) return ''
   const name = formatExpenseName(id, flatList.value)
@@ -589,6 +599,7 @@ async function uploadOne(filePath) {
         id: id || pendingId,
         previewUrl,
         localPath: filePath,
+        fileName: data.fileName || data.file_name || '',
         _pending: false,
         _existing: false
       }
@@ -696,6 +707,7 @@ async function loadEditData(id) {
         mapped.push({
           id: String(a.id),
           previewUrl,
+          fileName: a.fileName || a.file_name || '',
           _pending: false,
           _existing: true
         })

+ 17 - 3
miniprogram/pages/bx/reimburse/detail.vue

@@ -137,9 +137,9 @@
           <view class="detail-info-card__title">申请附件</view>
           <view v-if="attachments.length" class="att-grid">
             <view
-              v-for="file in attachments"
+              v-for="(file, idx) in attachments"
               :key="file.id"
-              class="att-img"
+              class="att-img att-img--with-name"
               @click="previewAtt(file)"
             >
               <image
@@ -150,6 +150,7 @@
               <view v-else class="detail-section-empty" style="border: none; padding: 8px">
                 文件
               </view>
+              <text class="att-img__name">{{ attachmentDisplayName(file, idx) }}</text>
             </view>
           </view>
           <view v-else class="detail-section-empty">暂无申请附件</view>
@@ -239,6 +240,7 @@ import {
 } from '@/utils/bxFormat'
 import { getSafeAreaStyle } from '@/utils/safeArea'
 import { useUserStore } from '@/stores/user'
+import { buildApplyAttachmentDisplayName } from '@/utils/bxAttachmentDisplayName'
 
 const safeAreaStyle = getSafeAreaStyle()
 const userStore = useUserStore()
@@ -298,6 +300,14 @@ function previewAtt(file) {
   uni.previewImage({ urls: [file.previewUrl], current: file.previewUrl })
 }
 
+function attachmentDisplayName(file, index) {
+  return buildApplyAttachmentDisplayName({
+    remark: detail.value?.remark || '',
+    originalFileName: file.fileName || '',
+    index1: index + 1
+  })
+}
+
 async function loadExpenseFlat() {
   try {
     const res = await expenseItemApi.tree()
@@ -340,7 +350,11 @@ async function loadDetail() {
 
   try {
     const attRes = await attachmentApi.listByBiz('reimburse_apply', id)
-    const list = (attRes.data || []).map((a) => ({ ...a, previewUrl: '' }))
+    const list = (attRes.data || []).map((a) => ({
+      ...a,
+      fileName: a.fileName || a.file_name || '',
+      previewUrl: ''
+    }))
     await Promise.all(
       list
         .filter((a) => (a.fileType || '').startsWith('image/'))

+ 32 - 0
miniprogram/styles/bx-theme.scss

@@ -594,6 +594,38 @@
   height: 100%;
 }
 
+.bx-page .att-img--with-name {
+  height: auto;
+  overflow: visible;
+  background: transparent;
+  border: none;
+}
+
+.bx-page .att-img--with-name image,
+.bx-page .att-img--with-name > .detail-section-empty {
+  display: block;
+  width: 72px;
+  height: 72px;
+  border-radius: 8px;
+  overflow: hidden;
+  background: var(--bg);
+  border: 1px solid var(--border);
+  box-sizing: border-box;
+}
+
+.bx-page .att-img__name {
+  display: block;
+  width: 72px;
+  margin-top: 4px;
+  font-size: 11px;
+  line-height: 1.3;
+  color: var(--text-muted, #64748b);
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  text-align: center;
+}
+
 .bx-page .att-img .del {
   position: absolute;
   top: 2px;