Преглед изворни кода

修复了录用审批,离职申请,离职交接审核详情中附件无法查看的问题

lihaiting пре 1 дан
родитељ
комит
e47ee6f68e

+ 32 - 0
.workbuddy/memory/2026-10-15.md

@@ -0,0 +1,32 @@
+# 2026-10-15 工作日志
+
+## 修复 BPM 审批详情附件查看功能
+
+美羊羊反馈:录用审批、办理入职、转正申请、合同签署、岗位调动、离职申请、离职交接的审批详情里附件都看不了。
+
+### 诊断结果
+
+| 审批类型 | 问题 | 修复 |
+|---------|------|------|
+| 录用审批 | 附件只用 `<em>` 纯文本显示文件名,没 fileMain 组件;API 只提取了 attachmentNames 丢弃了 fileId | API 补 attachmentFileIds,详情用 fileMain 替换纯文本 |
+| 办理入职 | 代码 OK,但缺 `:view-disabled`,空数据时按钮可点击打开空弹窗 | 加 `:view-disabled="!resumeFileIds.length"` |
+| 转正申请 | 代码 OK,无需修改 | — |
+| 合同签署 | 代码 OK,无需修改 | — |
+| 岗位调动 | 代码 OK,无需修改 | — |
+| 离职申请 | 模板完全没有附件展示区域,form 有 approvalDocumentFileId 字段但未使用 | 加附件 section + fileMain |
+| 离职交接 | 整个文件没有任何附件相关代码 | 加附件区域 + data/approvalFileIds + bootstrap 取值 |
+
+### 改动文件
+
+1. `src/api/bpm/components/offerApproval/index.js` — adaptHiringApproval 增加 attachmentFileIds
+2. `src/views/bpm/handleTask/components/offerApproval/offerApprovalDetail.vue` — 用 fileMain 替换纯文本附件展示
+3. `src/views/bpm/handleTask/components/resignationApplication/resignationApplicationDetail.vue` — 新增附件展示区域
+4. `src/views/bpm/handleTask/components/resignationHandoverOrder/resignationHandoverOrderDetail.vue` — 新增附件展示区域
+5. `src/views/bpm/handleTask/components/hiringApproval/hiringApprovalDetail.vue` — 加 :view-disabled
+
+### 关键点
+
+- fileMain 是全局注册组件(main.js `Vue.component('fileMain', fileMain)`),所有 .vue 可直接用
+- fileMain type="view" 模式:单文件直接 window.open 预览,多文件打开列表弹窗(含浏览/下载)
+- 附件 fileId 来源:录用审批用 attachments[].fileId/id,其余审批单用 approvalDocumentFileId 字段
+- 离职交接接口无适配层,用 pick 兼容 approvalDocumentFileId / attachmentFileId 两种字段名

+ 3 - 0
src/api/bpm/components/offerApproval/index.js

@@ -76,6 +76,9 @@ export function adaptHiringApproval(raw = {}) {
     status: HIRING_STATUS_LABELS[statusCode] || raw.approvalStatus || '-',
     remark: raw.remark || raw.approvalComment || '',
     attachments,
+    attachmentFileIds: attachments
+      .map((item) => item.fileId || item.id)
+      .filter((id) => id != null && id !== ''),
     attachmentNames: attachments
       .map((item) => item.fileName || item.name)
       .filter(Boolean),

+ 1 - 1
src/views/bpm/handleTask/components/hiringApproval/hiringApprovalDetail.vue

@@ -209,7 +209,7 @@
           <div class="attach-row">
             <label>简历</label>
             <div class="attach-content">
-              <fileMain v-model="resumeFileIds" type="view" size="small" />
+              <fileMain v-model="resumeFileIds" type="view" size="small" :view-disabled="!resumeFileIds.length" />
             </div>
           </div>
         </section>

+ 9 - 12
src/views/bpm/handleTask/components/offerApproval/offerApprovalDetail.vue

@@ -107,17 +107,12 @@
       </div>
       <div class="detail-block">
         <span>附件</span>
-        <div
-          class="file-tags"
-          v-if="form.attachmentNames && form.attachmentNames.length"
-        >
-          <em
-            v-for="(name, index) in form.attachmentNames"
-            :key="name + index"
-            class="file-tag"
-            >{{ name }}</em
-          >
-        </div>
+        <fileMain
+          v-if="attachmentFileIds.length"
+          v-model="attachmentFileIds"
+          type="view"
+          size="small"
+        />
         <p v-else class="detail-muted">暂无附件</p>
       </div>
       <div class="detail-block" v-if="form.remark">
@@ -163,7 +158,8 @@ export default {
   data() {
     return {
       loading: false,
-      form: emptyForm()
+      form: emptyForm(),
+      attachmentFileIds: []
     };
   },
   watch: {
@@ -183,6 +179,7 @@ export default {
           ...emptyForm(),
           ...(await getHiringApprovalById(id))
         };
+        this.attachmentFileIds = this.form.attachmentFileIds || [];
       } catch (error) {
         this.form = emptyForm();
         this.$message.error(error.message || '录用审批详情加载失败');

+ 25 - 1
src/views/bpm/handleTask/components/resignationApplication/resignationApplicationDetail.vue

@@ -75,6 +75,26 @@
         </div>
       </div>
     </section>
+
+    <!-- 附件 -->
+    <section class="detail-section">
+      <div class="info-card info-card--body">
+        <div class="kv-grid">
+          <div class="kv-item kv-item--full">
+            <span class="kv-item__label">附件</span>
+            <span class="kv-item__value">
+              <fileMain
+                v-if="approvalFileIds.length"
+                v-model="approvalFileIds"
+                type="view"
+                size="small"
+              />
+              <span v-else style="color: #909399">暂无附件</span>
+            </span>
+          </div>
+        </div>
+      </div>
+    </section>
   </main>
 </template>
 
@@ -162,7 +182,8 @@ export default {
     return {
       loading: false,
       form: empty(),
-      employeeInfo: {}
+      employeeInfo: {},
+      approvalFileIds: []
     };
   },
   computed: {
@@ -287,9 +308,12 @@ export default {
           }
         }
         this.employeeInfo = this.mapEmployeeInfo(resignation, employee);
+        const fileId = this.form.approvalDocumentFileId;
+        this.approvalFileIds = fileId ? [fileId] : [];
       } catch (error) {
         this.form = empty();
         this.employeeInfo = {};
+        this.approvalFileIds = [];
         if (process.env.NODE_ENV !== 'production') {
           console.warn('[ResignationDetail] 加载离职单失败:', error);
         }

+ 20 - 1
src/views/bpm/handleTask/components/resignationHandoverOrder/resignationHandoverOrderDetail.vue

@@ -181,6 +181,20 @@
         </div>
         <p class="detail-description">{{ form.remark }}</p>
       </div>
+
+      <!-- 附件 -->
+      <div class="detail-section-card detail-section-card--gap">
+        <div class="detail-section-head">
+          <h3>附件</h3>
+        </div>
+        <fileMain
+          v-if="approvalFileIds.length"
+          v-model="approvalFileIds"
+          type="view"
+          size="small"
+        />
+        <p v-else class="detail-description">暂无附件</p>
+      </div>
     </div>
   </main>
 </template>
@@ -307,7 +321,9 @@ export default {
       /** 该员工最新入职物品领用单号 */
       receiptCode: '',
       /** 员工缓存:接收人 / 交接人姓名回显 */
-      employeeMap: {}
+      employeeMap: {},
+      /** 附件文件 ID 列表 */
+      approvalFileIds: []
     };
   },
   computed: {
@@ -352,6 +368,8 @@ export default {
         const detail = await getHandoverById(id);
         this.form = this.mapForm(detail);
         this.items = this.mapItems(detail);
+        const attachId = pick(detail, ['approvalDocumentFileId', 'attachmentFileId']);
+        this.approvalFileIds = attachId ? [attachId] : [];
         await Promise.all([
           this.loadEmployee(this.form.userId),
           this.loadReceivers(detail),
@@ -363,6 +381,7 @@ export default {
         this.assetRows = [];
         this.receiptCode = '';
         this.employeeMap = {};
+        this.approvalFileIds = [];
         if (process.env.NODE_ENV !== 'production') {
           console.warn('[ResignationHandoverOrderDetail] 加载交接单失败:', error);
         }

+ 2 - 2
vue.config.js

@@ -44,9 +44,9 @@ module.exports = {
         // target: 'http://192.168.1.251:18186',
         // target: 'http://192.168.1.251:18086',
         // target: 'http://192.168.1.3:18086',
-        target: 'http://aiot.zoomwin.com.cn:51001/api',
+        // target: 'http://aiot.zoomwin.com.cn:51001/api',
         // target: 'http://192.168.1.3:18086',
-        // target: 'http://192.168.1.147:18086', // 陈兵
+        target: 'http://192.168.1.147:18086', // 陈兵
         // target: 'http://192.168.1.116:18086', // 赵沙金
         // target: 'http://192.168.1.113:18086', // 郭丹