spring
10 小时以前 3ea1ff641e1c680a5a1727fb4034797bfe65d93e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<template>
  <view class="file-page">
    <PageHeader title="附件管理" @back="goBack" />
 
    <view class="file-list">
      <view v-if="files.length > 0">
        <view v-for="(f, idx) in files" :key="f.id || idx" class="file-item">
          <view class="file-info">
            <text class="file-name">{{ f.name }}</text>
          </view>
          <view class="file-actions">
            <view class="btn-link" @click="previewFile(f)">预览</view>
            <view class="btn-link danger" @click="confirmDelete(f)">删除</view>
          </view>
        </view>
      </view>
      <view v-else class="empty">暂无附件</view>
    </view>
 
    <view class="upload-bar">
      <view class="btn-upload" @click="chooseFile">上传附件</view>
    </view>
  </view>
</template>
 
<script setup>
import { ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import PageHeader from '@/components/PageHeader.vue'
import config from '@/config'
import { getToken } from '@/utils/auth'
import { qualityInspectFileAdd, qualityInspectFileDel, qualityInspectFileListPage } from '@/api/qualityManagement/qualityInspectFile.js'
 
const inspectId = ref('')
const files = ref([])
 
const getList = () => {
  if (!inspectId.value) return
  qualityInspectFileListPage({ inspectId: inspectId.value, current: 1, size: 200 })
    .then(res => {
      files.value = res?.data?.records || []
    })
    .catch(() => { files.value = [] })
}
 
const chooseFile = () => {
  if (!inspectId.value) {
    uni.showToast({ title: '缺少检验记录ID', icon: 'none' })
    return
  }
  uni.chooseFile({
    count: 1,
    success: (res) => {
      const path = res?.tempFiles?.[0]?.path
      const name = res?.tempFiles?.[0]?.name
      if (!path) return
      uploadOne(path, name)
    }
  })
}
 
const uploadOne = (filePath, originalName) => {
  const token = getToken()
  if (!token) {
    uni.showToast({ title: '未登录', icon: 'none' })
    return
  }
  uni.showLoading({ title: '上传中...', mask: true })
  uni.uploadFile({
    url: config.baseUrl + '/file/upload',
    filePath,
    name: 'file',
    header: { Authorization: 'Bearer ' + token },
    success: (res) => {
      uni.hideLoading()
      try {
        const resp = JSON.parse(res.data || '{}')
        if (resp.code !== 200) throw new Error('upload fail')
        const fileRow = {
          inspectId: inspectId.value,
          name: resp.data?.originalName || originalName || '附件',
          url: resp.data?.tempPath
        }
        qualityInspectFileAdd(fileRow).then(() => {
          uni.showToast({ title: '上传成功', icon: 'success' })
          getList()
        })
      } catch (e) {
        uni.showToast({ title: '上传失败', icon: 'none' })
      }
    },
    fail: () => {
      uni.hideLoading()
      uni.showToast({ title: '上传失败', icon: 'none' })
    }
  })
}
 
const previewFile = (f) => {
  const url = f?.url
  if (!url) return
  // H5/APP 统一用外部打开
  uni.navigateTo({
    url: `/pages/inspectionUpload/filePreview?url=${encodeURIComponent(url)}`
  })
}
 
const confirmDelete = (f) => {
  if (!f?.id) return
  uni.showModal({
    title: '删除',
    content: '确认删除该附件?',
    success: (r) => {
      if (!r.confirm) return
      qualityInspectFileDel([f.id]).then(() => {
        uni.showToast({ title: '删除成功', icon: 'success' })
        getList()
      })
    }
  })
}
 
onLoad((options) => {
  inspectId.value = options?.id || ''
  if (!inspectId.value) {
    const cached = uni.getStorageSync('rawMaterialFilesCtx')
    if (cached) {
      try {
        const payload = typeof cached === 'string' ? JSON.parse(cached) : cached
        inspectId.value = payload?.id || ''
        uni.removeStorageSync('rawMaterialFilesCtx')
      } catch (e) {
        uni.removeStorageSync('rawMaterialFilesCtx')
      }
    }
  }
})
 
onShow(() => {
  getList()
})
 
const goBack = () => uni.navigateBack()
</script>
 
<style lang="scss" scoped>
.file-page { min-height: 100vh; background: #f5f5f5; padding-bottom: 120rpx; }
.file-list { margin: 24rpx; background: #fff; border-radius: 16rpx; padding: 12rpx 24rpx; }
.file-item { padding: 20rpx 0; border-bottom: 1rpx solid #eee; display: flex; justify-content: space-between; align-items: center; gap: 16rpx; }
.file-item:last-child { border-bottom: 0; }
.file-name { font-size: 28rpx; color: #333; }
.file-actions { display: flex; gap: 20rpx; }
.btn-link { color: #2979ff; font-size: 26rpx; }
.btn-link.danger { color: #f56c6c; }
.empty { text-align: center; padding: 60rpx 0; color: #999; font-size: 28rpx; }
.upload-bar { position: fixed; left: 0; right: 0; bottom: 0; padding: 16rpx 24rpx calc(16rpx + env(safe-area-inset-bottom)); background: #fff; box-shadow: 0 -4rpx 16rpx rgba(0,0,0,0.04); }
.btn-upload { height: 88rpx; border-radius: 999rpx; background: #2979ff; color: #fff; font-size: 30rpx; display: flex; align-items: center; justify-content: center; }
</style>