// components/fakuan-list/fakuan-list.js import request from '../../../../utils/request.js'; const app = getApp(); const MEIYE_TIAOSHU = 5; Component({ properties: { status: { type: Number, value: 1, observer: 'reload' }, searchDingdan: { type: String, value: '', observer: 'reload' }, trigger: { type: Number, value: 0, observer: 'reload' } }, data: { list: [], page: 1, hasMore: true, loading: false, loadingMore: false, ossImageUrl: app.globalData.ossImageUrl || '', // 详情弹窗 showDetail: false, detailItem: null, // 申诉弹窗 showShensu: false, shensuLiyou: '', shensuTupian: [], uploading: false, uploadProgress: { current: 0, total: 0 }, uploadProgressWidth: '0%', // 支付弹窗 showPay: false, payFadan: null }, lifetimes: { attached() { this.reload(); } }, methods: { // ==================== 数据加载 ==================== reload() { this.setData({ page: 1, list: [], hasMore: true }); this.loadData(); }, async loadData(isLoadMore = false) { // 防止重复请求 if (this.data.loading || this.data.loadingMore) return; if (!isLoadMore) { this.setData({ loading: true }); } else { // 加载更多时,如果后端已经告知没有更多数据,不发送请求 if (!this.data.hasMore) { wx.showToast({ title: '没有更多了', icon: 'none', duration: 1000 }); return; } this.setData({ loadingMore: true }); } try { const res = await request({ url: '/yonghu/dsfklbhq', method: 'POST', data: { page: this.data.page, page_size: MEIYE_TIAOSHU, zhuangtai: this.data.status, sousuo_dingdan_id: this.data.searchDingdan } }); if (res.statusCode === 200 && res.data.code === 0) { const data = res.data.data; const newList = isLoadMore ? this.data.list.concat(data.list || []) : (data.list || []); this.setData({ list: newList, hasMore: data.has_more || false, // 以后端返回为准 page: isLoadMore ? this.data.page + 1 : 2, // 首次加载后页码为2 loading: false, loadingMore: false }); } else { wx.showToast({ title: res.data?.msg || '加载失败', icon: 'none' }); this.setData({ loading: false, loadingMore: false }); } } catch (e) { wx.showToast({ title: '网络请求失败', icon: 'none' }); this.setData({ loading: false, loadingMore: false }); } }, loadMore() { if (this.data.list.length === 0) return; this.loadData(true); }, // ==================== 详情弹窗 ==================== openDetail(e) { const item = e.currentTarget.dataset.item; this.setData({ showDetail: true, detailItem: item }); }, closeDetail() { this.setData({ showDetail: false, detailItem: null }); }, // ==================== 申诉逻辑 ==================== openShensu() { const item = this.data.detailItem; if (item.bohuiliyou) { wx.showToast({ title: '该罚单申诉已被驳回', icon: 'none' }); return; } const existingImgs = (item.shensu_tupian || []).map(url => this.getFullUrl(url)); this.setData({ showShensu: true, shensuLiyou: item.shensuliyou || '', shensuTupian: existingImgs, uploading: false, uploadProgress: { current: 0, total: 0 }, uploadProgressWidth: '0%' }); }, closeShensu() { this.setData({ showShensu: false }); }, onShensuInput(e) { this.setData({ shensuLiyou: e.detail.value.slice(0, 500) }); }, chooseImage() { const remain = 9 - this.data.shensuTupian.length; if (remain <= 0) return; wx.chooseMedia({ count: remain, mediaType: ['image'], sourceType: ['album', 'camera'], success: (res) => { const newImgs = [...this.data.shensuTupian, ...res.tempFiles.map(f => f.tempFilePath)]; this.setData({ shensuTupian: newImgs.slice(0, 9) }); } }); }, deleteShensuImg(e) { const arr = this.data.shensuTupian; arr.splice(e.currentTarget.dataset.index, 1); this.setData({ shensuTupian: arr }); }, previewImage(e) { wx.previewImage({ current: e.currentTarget.dataset.url, urls: [e.currentTarget.dataset.url] }); }, previewLocalImg(e) { const idx = e.currentTarget.dataset.index; wx.previewImage({ current: this.data.shensuTupian[idx], urls: this.data.shensuTupian }); }, // ==================== 提交流程 ==================== async submitShensu() { if (!this.data.shensuLiyou.trim()) { wx.showToast({ title: '请输入申诉理由', icon: 'none' }); return; } wx.showLoading({ title: '提交中...' }); try { const newLocalPaths = this.data.shensuTupian.filter(path => !path.startsWith('http')); let finalUrls = []; if (newLocalPaths.length > 0) { finalUrls = await this.piliangShangchuanShensuTupian(newLocalPaths); if (!finalUrls) { wx.hideLoading(); return; } } const oldRemoteRelative = this.data.shensuTupian .filter(path => path.startsWith('http')) .map(url => url.replace(this.data.ossImageUrl, '').replace(/^\//, '')); const allUrls = oldRemoteRelative.concat(finalUrls); await this.doSubmitShensu(allUrls); } catch (err) { console.error('提交申诉失败', err); wx.showToast({ title: err.message || '提交失败', icon: 'none' }); } finally { wx.hideLoading(); } }, async doSubmitShensu(tupianUrls) { const res = await request({ url: '/yonghu/fkss', method: 'POST', data: { fadan_id: this.data.detailItem.id, shensu_liyou: this.data.shensuLiyou, shensu_tupian_urls: tupianUrls } }); if (res.statusCode === 200 && res.data.code === 0) { wx.showToast({ title: '申诉已提交', icon: 'success' }); this.setData({ showShensu: false, showDetail: false }); this.reload(); } else { throw new Error(res.data?.msg || '提交失败'); } }, // ==================== 图片上传到COS ==================== async piliangShangchuanShensuTupian(localPaths) { const total = localPaths.length; if (!total) return []; this.setData({ uploading: true, uploadProgress: { current: 0, total: total }, uploadProgressWidth: '0%' }); let tokenData; try { const credRes = await request({ url: '/dingdan/dsscpz', method: 'POST', data: { dingdan_id: this.data.detailItem.guanliandingdan_id || '', fadan_id: this.data.detailItem.id, yongtu: 'fakuan' } }); if (credRes.data.code !== 0) throw new Error(credRes.data.msg || '凭证获取失败'); tokenData = credRes.data.data; } catch (e) { wx.showToast({ title: '获取上传凭证失败', icon: 'none' }); this.setData({ uploading: false }); return null; } const COS = require('../../../../utils/cos-wx-sdk-v5.js'); const credentials = tokenData.credentials || tokenData; const cos = new COS({ SimpleUploadMethod: 'putObject', getAuthorization: (options, callback) => { callback({ TmpSecretId: credentials.tmpSecretId, TmpSecretKey: credentials.tmpSecretKey, SecurityToken: credentials.sessionToken || '', StartTime: tokenData.startTime, ExpiredTime: tokenData.expiredTime }); } }); const bucket = tokenData.bucket || 'julebu-1361527063'; const region = tokenData.region || 'ap-shanghai'; const yonghuid = app.globalData.userInfo?.yonghuid || wx.getStorageSync('uid') || '0000000'; const fadanId = this.data.detailItem.id; const keys = []; for (let i = 0; i < total; i++) { keys.push(`fakuan/dashoufakuan/dashoufakuanshensu/${yonghuid}_${fadanId}_${Date.now() + i}.jpg`); } for (let i = 0; i < total; i++) { try { await new Promise((resolve, reject) => { const timeoutId = setTimeout(() => resolve(), 2000); cos.uploadFile({ Bucket: bucket, Region: region, Key: keys[i], FilePath: localPaths[i], onProgress: (info) => { if (Math.round(info.percent * 100) === 100) { clearTimeout(timeoutId); resolve(); } } }, (err) => { clearTimeout(timeoutId); if (err) reject(err); else resolve(); }); }); } catch (err) { wx.showToast({ title: `第 ${i + 1} 张上传失败`, icon: 'none' }); this.setData({ uploading: false }); return null; } const done = i + 1; this.setData({ uploadProgress: { current: done, total: total }, uploadProgressWidth: `${((done / total) * 100).toFixed(0)}%` }); } this.setData({ uploading: false }); return keys; }, // ==================== 缴纳支付 ==================== startPay() { this.setData({ showDetail: false, showPay: true, payFadan: this.data.detailItem }); }, onPayClose() { this.setData({ showPay: false, payFadan: null }); }, onPaySuccess() { this.setData({ showPay: false, payFadan: null }); this.reload(); }, // ==================== 工具方法 ==================== getFullUrl(url) { if (!url) return ''; if (url.startsWith('http')) return url; return this.data.ossImageUrl + url; } } });