From 9d4f45939870dde9b59d354616d87536d6274ef1 Mon Sep 17 00:00:00 2001 From: p-honggang.li <p-honggang.li@pcitc.com> Date: 星期三, 03 九月 2025 18:30:07 +0800 Subject: [PATCH] 修改交易员确认 --- src/views/tradeManage/confirm/index.vue | 695 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 522 insertions(+), 173 deletions(-) diff --git a/src/views/tradeManage/confirm/index.vue b/src/views/tradeManage/confirm/index.vue index cec4efa..0392ee4 100644 --- a/src/views/tradeManage/confirm/index.vue +++ b/src/views/tradeManage/confirm/index.vue @@ -170,16 +170,29 @@ {{ formatFileSize(row.size) }} </template> </el-table-column> - <el-table-column label="鎿嶄綔" width="100"> + <el-table-column label="鎿嶄綔" width="180"> <template #default="{ row }"> - <el-button - type="text" - size="small" - class="preview-btn" - @click="handlePreview(row)" - > - 棰勮 - </el-button> + <div class="file-actions"> + <el-button + type="text" + size="small" + class="preview-btn" + @click="handlePreview(row)" + v-if="isPreviewable(row)" + :disabled="!isFileUploaded(row)" + > + 棰勮 + </el-button> + <el-button + type="text" + size="small" + class="download-btn" + @click="handleDownload(row)" + :disabled="!isFileUploaded(row)" + > + 涓嬭浇 + </el-button> + </div> </template> </el-table-column> </el-table> @@ -191,49 +204,24 @@ <div class="title">浜ゆ槗淇℃伅澶囨敞</div> <el-table :data="form.items" border class="mt10 remark-table"> <el-table-column label="璇︽儏" prop="name" min-width="200" /> - <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200"> - <template #default="{ row, $index }"> - <el-date-picker - v-model="form.items[$index].start" - type="date" - value-format="YYYY-MM-DD" - placeholder="閫夋嫨鏃ユ湡" - size="small" - style="width: 100%" - /> - </template> - </el-table-column> - <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200"> - <template #default="{ row, $index }"> - <div class="end-time-wrapper"> - <el-date-picker - v-model="form.items[$index].end" - type="date" - value-format="YYYY-MM-DD" - placeholder="閫夋嫨鏃ユ湡" - size="small" - style="width: 100%" - :disabled="form.items[$index].forever" - /> - <el-checkbox - v-model="form.items[$index].forever" - class="forever-checkbox" - @change="handleForeverChange($index)" - > - 姘镐箙 - </el-checkbox> - </div> - </template> - </el-table-column> - <el-table-column label="澶囨敞" min-width="300"> - <template #default="{ row, $index }"> - <el-input - v-model="form.items[$index].remark" - placeholder="璇疯緭鍏ュ娉�" - size="small" - /> - </template> - </el-table-column> + <el-table-column label="鎺堟潈寮�濮嬫椂闂�" width="200"> + <template #default="{ row, $index }"> + <span>{{ form.items[$index].start || '-' }}</span> + </template> + </el-table-column> + <el-table-column label="鎺堟潈缁撴潫鏃堕棿" width="200"> + <template #default="{ row, $index }"> + <div class="end-time-wrapper"> + <span v-if="form.items[$index].forever" class="forever-text">姘镐箙</span> + <span v-else>{{ form.items[$index].end || '-' }}</span> + </div> + </template> + </el-table-column> + <el-table-column label="澶囨敞" min-width="300"> + <template #default="{ row, $index }"> + <span>{{ form.items[$index].remark || '-' }}</span> + </template> + </el-table-column> </el-table> <div class="action-buttons"> <el-button @click="goBack">杩斿洖</el-button> @@ -247,11 +235,17 @@ import { onMounted, reactive, ref, computed, type CSSProperties } from 'vue' import { useRoute, useRouter } from 'vue-router' import { Document, User, Goods, List } from '@element-plus/icons-vue' -import { fetchOrderDetail, confirmTrade } from '@/api/tradeManage' -import { ElMessage } from 'element-plus' +import { ElMessage, ElMessageBox } from 'element-plus' +import orderApi from '@/api/orderApi' +import pointsApi from '@/api/pointsApi' // 鏂板绉垎API瀵煎叆 +import { useUserInfo } from '@/stores/modules/userInfo' +import createAxios from '@/utils/axios' +import productApi from '@/api/productApi' +import sysUserService from '@/api/sysUser' const route = useRoute() const router = useRouter() +const userStore = useUserInfo() const detail = reactive<any>({ items: [] }) const form = reactive<any>({ items: [] }) const fileList = ref<any[]>([]) @@ -277,123 +271,262 @@ return [...detail.items, summaryRow] }) -onMounted(async () => { - // 浣跨敤鍓嶇妯℃嫙鏁版嵁浠ヤ究寮�鍙� UI锛堜笉鏀瑰姩鍚庣鏈嶅姟锛� - const mockDetail = { - orderNo: '4348442557619205545', - resourceTypeName: '杞欢浜у搧', - status: 'WAIT_CONFIRM', - statusName: '寰呯‘璁�', - applyTime: '2025-05-21 10:00:00', - unitName: '涓氦鏂硅繙寤鸿鏈夐檺鍏徃', - userName: '寮犻潤', - userAccount: 'L20159922', - userDept: '淇℃伅涓績', - userPhone: '13800000000', - productName: '涓氦鏂硅繙鏅鸿兘瀹炴祴瀹為噺绠$悊绯荤粺', - supplier: '涓氦鏂硅繙绉戞妧鏈夐檺鍏徃', - industry: '寤虹瓚宸ョ▼', - projectUnit: '鍦熷缓宸ョ▼', - productType: '杞欢搴�', - productDesc: - '闈㈠悜宸ョ▼椤圭洰鐨勮川閲忓疄娴嬪疄閲忔暟瀛楀寲绠$悊绯荤粺锛屾敮鎸佹爣鍑嗗寲閲囬泦銆佽嚜鍔ㄧ粺璁′笌杩囩▼绠℃帶銆�', - items: [ - { - id: '1', - name: '浼佷笟绉佹湁SaaS鐗堣鍙�', - saleType: '涔版柇', - accountCount: 50, - customerTarget: '浼佷笟', - concurrentNodes: 50, - pricePoint: 50000, - priceCash: 0, - quantity: 1, - period: 0, - }, - { - id: '2', - name: '浼佷笟绉佹湁SaaS鐗圤TA鍗囩骇鏈嶅姟', - saleType: 'OTA鏈嶅姟', - accountCount: 50, - customerTarget: '浼佷笟', - concurrentNodes: 50, - pricePoint: 0, - priceCash: 7500, - quantity: 1, - period: 1, - }, - { - id: '3', - name: '浼佷笟绉佹湁SaaS鐗堢敤鎴峰閲忓寘', - saleType: '绉佹湁澧為噺鍖�', - accountCount: 100, - customerTarget: '浼佷笟', - concurrentNodes: 100, - pricePoint: 0, - priceCash: 0, - priceProtocol: true, - quantity: 1, - period: 1, - }, - { - id: '4', - name: '涓汉鍏湁SaaS鐗堣鍙�', - saleType: '绉佹湁澧為噺鍖�', - accountCount: 50, - customerTarget: '涓汉', - concurrentNodes: 50, - pricePoint: 0, - priceCash: 0, - quantity: 1, - period: 0, - }, - ], - pointTotal: '50,000', - cashTotal: '7,500', - } +// 鐘舵�佹槧灏勶紙鍚庣涓枃 -> 鍓嶇鏋氫妇锛� +const statusServerToUi: Record<string, string> = { + '寰呬笂浼犳枃浠�': 'WAIT_UPLOAD', + '寰呮巿鏉�': 'WAIT_AUTHORIZE', + '寰呬氦鏄撶‘璁�': 'WAIT_CONFIRM', + '宸插畬鎴�': 'COMPLETED', + '宸茶瘎浠�': 'EVALUATED', +} - Object.assign(detail, mockDetail) - form.items = (detail.items || []).map((item: any, index: number) => ({ - name: item.name, - start: '2025-06-01', - end: index === 0 || index === 3 ? '' : '2025-06-01', - forever: index === 0 || index === 3, - remark: index === 3 ? '寮�閫氱鐞嗗憳璐﹀彿1涓�,璐﹀彿admin' : '寮�閫氱鐞嗗憳璐﹀彿1涓�,璐﹀彿admin,鐧诲綍绠$悊鍛樿处鍙峰彲绠$悊鏅�氱敤鎴�' - })) +const formatDateTime = (val?: string) => (val ? val.replace('T', ' ').slice(0, 19) : '') + +const normalizePriceType = (val?: string): 'points' | 'currency' | 'agreement' | 'free' => { + if (!val) return 'currency' + const s = String(val) + if (/(绉垎|points)/i.test(s)) return 'points' + if (/(鍗忚|agreement)/i.test(s)) return 'agreement' + if (/(鍏嶈垂|free)/i.test(s)) return 'free' + return 'currency' +} + +onMounted(async () => { + const orderId = String(route.params.id || '') + if (!orderId) return - // 娣诲姞妯℃嫙鏂囦欢鏁版嵁鐢ㄤ簬灞曠ず - fileList.value = [ - { - name: '绛惧瓧鐩栫珷鏂囦欢.pdf', - size: 2621440, // 2.5MB - uid: '1', - status: 'success' - }, - { - name: 'API Keys.txt', - size: 354, // 354 Bytes - uid: '2', - status: 'success' + try { + const res = (await orderApi.getOrderDetail(orderId)) as any + const data = res?.data || {} + + const statusName: string = data.orderStatus || '' + const uiStatus = statusServerToUi[statusName] || 'INFO' + + // 鏍规嵁浜у搧id鑾峰彇浜у搧淇℃伅锛屾洿鏂板ご閮ㄥ睍绀� + try { + if (data.productId) { + const detailRes: any = await productApi.getProductById({ id: data.productId }) + if (detailRes?.code === 200 && detailRes.data) { + // 鐢ㄤ骇鍝佽鎯呰ˉ鍏ㄥご淇℃伅 + data.productName = detailRes.data.name || data.productName + data.providerName = detailRes.data.submissionUnit || data.providerName + data.industry = detailRes.data.industrialChainName || data.industry + data.productDesc = detailRes.data.describe || data.productDesc + data.projectUnit = detailRes.data.importantAreaName || data.productDesc + data.productType = detailRes.data.typeName || data.productDesc + } + } + } catch (e) { + // 蹇界暐浜у搧璇︽儏澶辫触锛屼笉闃诲璁㈠崟璇︽儏 } - ] - - // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹� - // const { data } = (await fetchOrderDetail({ id: route.params.id })) as any - // Object.assign(detail, data || {}) - // form.items = (detail.items || []).map(() => ({ start: '', end: '', forever: false, remark: '' })) + + // 鑾峰彇鐢ㄦ埛淇℃伅 + try { + const userRes: any = await sysUserService.getUserdetail({ userId: data.userId }) + if (userRes?.code === 200 && userRes.data) { + // 鐢ㄤ骇鍝佽鎯呰ˉ鍏ㄥご淇℃伅 + data.unitName = userRes.data.unitName || data.unitName + data.userName = userRes.data.name || data.userName + data.userDept = userRes.data.departmentName || data.userDept + data.userPhone = userRes.data.phone || data.userPhone + data.userAccount = userRes.data.username || data.userAccount + } + }catch (e){ + + } + + // 鏄犲皠璁㈠崟璇︽儏澶撮儴淇℃伅 + const head = { + orderNo: data.orderId, + resourceTypeName: '杞欢浜у搧', + status: uiStatus, + statusName, + applyTime: formatDateTime(data.applyTime), + unitName: data.unitName || '-', + userName: data.userName || '-', + userAccount: data.userAccount || '-', + userDept: data.userDept || '-', + userPhone: data.userPhone || '-', + productName: data.productName || '-', + supplier: data.providerName || '-', + industry: data.industry || '-', + projectUnit: data.projectUnit || '-', + productType: data.productType || '-', + productDesc: data.productDesc || '-', + providerId: data.providerId || '' + } + + // 鏄庣粏椤规槧灏� + const items: any[] = Array.isArray(data.orderDetails) + ? data.orderDetails.map((d: any, idx: number) => { + const pt = normalizePriceType(d.priceType) + return { + id: String(d.id ?? idx + 1), + name: d.suiteName, + saleType: d.salesForm, + accountCount: d.accountLimit, + customerTarget: d.customerType, + concurrentNodes: d.concurrentNodes, + pricePoint: pt === 'points' ? Number(d.unitPrice || 0) : 0, + priceCash: pt === 'currency' ? Number(d.unitPrice || 0) : 0, + priceProtocol: pt === 'agreement', + quantity: Number(d.quantity || 0), + period: Number(d.duration || 0), + remarks: d.remarks || '', // 鏂板 remarks 瀛楁 + } + }) + : [] + + // 姹囨�伙紙绠�鍗曠浉鍔狅細鍗曚环*鏁伴噺锛� + const pointTotalNum = items.reduce((sum, it) => sum + Number(it.pricePoint || 0) * Number(it.quantity || 0), 0) + const cashTotalNum = items.reduce((sum, it) => sum + Number(it.priceCash || 0) * Number(it.quantity || 0), 0) + + Object.assign(detail, head, { + items, + pointTotal: pointTotalNum.toLocaleString(), + cashTotal: cashTotalNum.toLocaleString(), + }) + + // 鍒濆鍖栬〃鍗曟暟鎹� + form.items = (detail.items || []).map((item: any, index: number) => { + // 璁$畻鎺堟潈缁撴潫鏃堕棿 + let endDate = '' + if (item.period > 0) { + // 濡傛灉鏈夋湡闄愶紝璁$畻缁撴潫鏃堕棿 + const startDate = new Date(data.applyTime || new Date()) + const endDateObj = new Date(startDate) + endDateObj.setFullYear(endDateObj.getFullYear() + item.period) + endDate = endDateObj.toISOString().split('T')[0] // 鏍煎紡鍖栦负 YYYY-MM-DD + } + + return { + name: item.name, + start: data.applyTime ? data.applyTime.split('T')[0] : '', // 浣跨敤璁㈠崟鐢宠鏃堕棿 + end: endDate, + forever: item.period === 0, // 鏈熼檺涓�0鏃惰缃负姘镐箙 + remark: item.remarks || '' // 浣跨敤濂椾欢淇℃伅涓殑remarks瀛楁 + } + }) + + // 鑾峰彇璁㈠崟闄勪欢鍒楄〃锛堝鏋滄湁鐨勮瘽锛� + if (data.attachments && Array.isArray(data.attachments)) { + fileList.value = data.attachments.map((file: any) => ({ + name: file.fileName || file.originalName, + size: file.fileSize || 0, + uid: file.id, + status: 'success', + url: file.fileUrl, + uploaded: true + })) + } else { + fileList.value = [] + } + } catch (error) { + console.error('鑾峰彇璁㈠崟璇︽儏澶辫触:', error) + ElMessage.error('鑾峰彇璁㈠崟璇︽儏澶辫触') + } }) const goBack = () => router.back() const submit = async () => { - // 妯℃嫙鎻愪氦鎴愬姛鍝嶅簲 - const mockResponse = { code: 200 } - - // 娉ㄩ噴鎺夊師鏈夌殑API璋冪敤锛屼娇鐢ㄦā鎷熸暟鎹� - // const { code } = (await confirmTrade({ id: route.params.id, ...form })) as any - - if (mockResponse.code === 200) { - ElMessage.success('鎻愪氦鎴愬姛') - router.back() + try { + const orderId = String(route.params.id || '') + const userId = userStore.getUserId ? Number(userStore.getUserId) : undefined + + if (!orderId || !userId) { + ElMessage.error('璁㈠崟ID鎴栫敤鎴稩D涓嶈兘涓虹┖') + return + } + + // 妫�鏌ヨ鍗曟槸鍚︽秹鍙婄Н鍒嗘墸鍑� + const hasPointsDeduction = detail.items && detail.items.some((item: any) => Number(item.pricePoint || 0) > 0) + + // if (hasPointsDeduction) { + // // 璁$畻闇�瑕佹墸鍑忕殑绉垎鎬婚 + // const totalPointsToDeduct = detail.items.reduce((sum: number, item: any) => { + // return sum + (Number(item.pricePoint || 0) * Number(item.quantity || 0)) + // }, 0) + // + // if (totalPointsToDeduct > 0) { + // // 鑾峰彇褰撳墠鐢ㄦ埛绉垎浣欓 + // try { + // const userPointsRes = await pointsApi.getUserPoints(userId) + // if (userPointsRes.code !== 200 || !userPointsRes.data) { + // ElMessage.error('鑾峰彇绉垎浣欓澶辫触') + // return + // } + // + // const currentPoints = userPointsRes.data.balance || 0 + // + // if (currentPoints < totalPointsToDeduct) { + // ElMessage.error(`绉垎浣欓涓嶈冻锛佸綋鍓嶇Н鍒嗭細${currentPoints.toLocaleString()}锛岄渶瑕佺Н鍒嗭細${totalPointsToDeduct.toLocaleString()}`) + // return + // } + // + // // 绉垎浣欓鍏呰冻锛岀户缁墽琛� + // console.log(`绉垎浣欓妫�鏌ラ�氳繃锛氬綋鍓�${currentPoints}锛岄渶瑕�${totalPointsToDeduct}`) + // } catch (error) { + // console.error('鑾峰彇绉垎浣欓澶辫触:', error) + // ElMessage.error('鑾峰彇绉垎浣欓澶辫触锛岃閲嶈瘯') + // return + // } + // } + // } + + // 纭鎿嶄綔 + await ElMessageBox.confirm('纭畾瑕佺‘璁や氦鏄擄紵', '纭鎿嶄綔', { + confirmButtonText: '纭畾', + cancelButtonText: '鍙栨秷', + type: 'warning' + }) + + // 濡傛灉娑夊強绉垎鎵e噺锛屽厛杩涜绉垎鎵e噺鍜屾祦姘磋褰� + if (hasPointsDeduction) { + const totalPointsToDeduct = detail.items.reduce((sum: number, item: any) => { + return sum + (Number(item.pricePoint || 0) * Number(item.quantity || 0)) + }, 0) + + if (totalPointsToDeduct > 0) { + try { + // 鑾峰彇鐢ㄦ埛鍗曚綅ID + const unitId = userStore.getUserInfo?.unitId || userStore.getUserInfo?.unitId || '' + + // 鑾峰彇褰撳墠璁㈣喘鐨勪骇鍝佸悕绉颁綔涓哄娉紙浣跨敤浜у搧鍚嶇О锛屼笉鏄浠跺悕绉帮級 + const productNames = detail.productName || '璁㈠崟浜ゆ槗鎵e噺绉垎' + + // 鍏堟墽琛岀Н鍒嗘墸鍑� + const deductRes: any = await pointsApi.deductPointsByFlow( + userId.toString(), + unitId, + totalPointsToDeduct, + orderId, + productNames || '璁㈠崟浜ゆ槗鎵e噺绉垎', // 浣跨敤浜у搧鍚嶇О浣滀负澶囨敞 + '绉垎浜ゆ槗', // 鏁版嵁绫诲埆 + detail.providerId + ) + if (!deductRes || deductRes.code !== 200) { + ElMessage.error(deductRes?.msg || deductRes?.message || '绉垎鎵e噺澶辫触锛屼氦鏄撶‘璁ょ粓姝�') + return + } + console.log(`绉垎鎵e噺鎴愬姛锛�${totalPointsToDeduct}`) + } catch (error) { + console.error('绉垎鎵e噺澶辫触:', error) + ElMessage.error('绉垎鎵e噺澶辫触锛屼氦鏄撶‘璁ょ粓姝�') + return + } + } + } + + // 绉垎鎵e噺鎴愬姛鍚庯紝鏇存柊璁㈠崟鐘舵�佽繘鍏ヤ笅涓�涓姸鎬� + await orderApi.updateOrderStatusToNext(orderId) + + ElMessage.success('浜ゆ槗纭鎴愬姛') + router.back() + } catch (error) { + if (error !== 'cancel') { + console.error('浜ゆ槗纭澶辫触:', error) + ElMessage.error('浜ゆ槗纭澶辫触') + } } } @@ -480,17 +613,202 @@ return parseFloat((size / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; -// 鏂囦欢棰勮澶勭悊 -const handlePreview = (file: any) => { - ElMessage.info(`棰勮鏂囦欢锛�${file.name}`) +// 鍒ゆ柇鏂囦欢鏄惁鍙瑙� +const isPreviewable = (file: any) => { + // 棣栧厛妫�鏌IME绫诲瀷 + const previewableTypes = [ + 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/webp', + 'text/plain', 'text/html', 'text/css', 'text/javascript', + 'application/pdf', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx + ] + + // 濡傛灉MIME绫诲瀷鍖归厤锛岀洿鎺ヨ繑鍥瀟rue + if (previewableTypes.includes(file.type || '')) { + return true + } + + // 濡傛灉MIME绫诲瀷涓虹┖鎴栦笉鍖归厤锛屾牴鎹枃浠舵墿灞曞悕鍒ゆ柇 + const fileName = file.name || '' + const fileExtension = fileName.toLowerCase().split('.').pop() + + const previewableExtensions = [ + 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', + 'txt', 'html', 'htm', 'css', 'js', + 'pdf', + 'docx', 'xlsx', 'pptx' + ] + + return previewableExtensions.includes(fileExtension) } -// 姘镐箙澶嶉�夋鍙樺寲澶勭悊 -const handleForeverChange = (index: number) => { - if (form.items[index].forever) { - form.items[index].end = '' +// 鍒ゆ柇鏂囦欢鏄惁宸蹭笂浼犳垚鍔� +const isFileUploaded = (file: any) => { + // 鏂囦欢鏈塽rl涓旂姸鎬佷负success琛ㄧず宸蹭笂浼犳垚鍔� + return file.url && (file.status === 'success' || file.uploaded) +} + +// 鏂囦欢棰勮 +const handlePreview = async (file: any) => { + if (!file.url) { + ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�') + return + } + + // 鑾峰彇鏂囦欢鎵╁睍鍚� + const fileName = file.name || '' + const fileExtension = fileName.toLowerCase().split('.').pop() + + let previewUrl = file.url + + // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼紭鍏堜娇鐢ㄩ瑙圲RL + if (file.url.includes('order-attachments')) { + try { + // 棣栧厛灏濊瘯鑾峰彇棰勮URL + const previewResponse = await createAxios({ + url: `/admin/file/preview`, + method: 'GET', + params: { + fileName: file.url + } + }) + + console.log('棰勮URL鍝嶅簲:', previewResponse) + + // 妫�鏌ュ搷搴旀牸寮� + const responseData = previewResponse as any + if (responseData && responseData.code === 200 && responseData.data) { + previewUrl = responseData.data + console.log('浣跨敤棰勮URL:', previewUrl) + } else { + console.log('棰勮URL鑾峰彇澶辫触锛屼娇鐢ㄤ笅杞芥柟寮�') + // 濡傛灉棰勮URL鑾峰彇澶辫触锛屽洖閫�鍒颁笅杞芥柟寮� + const response = await createAxios({ + url: `/admin/file/download`, + method: 'GET', + responseType: 'blob', + params: { + fileName: file.url, + originalName: file.name + } + }) + + // 鍒涘缓棰勮URL + const blob = new Blob([response as any]) + previewUrl = window.URL.createObjectURL(blob) + console.log('浣跨敤Blob URL:', previewUrl) + } + } catch (error) { + console.error('鑾峰彇鏂囦欢澶辫触:', error) + ElMessage.error('鑾峰彇鏂囦欢澶辫触锛屾棤娉曢瑙�') + return + } + } + + // 鍥剧墖鏂囦欢鐩存帴鍦ㄦ柊绐楀彛鎵撳紑 + if ((file.type && file.type.startsWith('image/')) || + ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) { + console.log('棰勮鍥剧墖鏂囦欢:', previewUrl) + window.open(previewUrl, '_blank') + return + } + + // PDF鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑 + if (file.type === 'application/pdf' || fileExtension === 'pdf') { + console.log('棰勮PDF鏂囦欢:', previewUrl) + window.open(previewUrl, '_blank') + return + } + + // 鏂囨湰鏂囦欢鍦ㄦ柊绐楀彛鎵撳紑 + if ((file.type && file.type.startsWith('text/')) || + ['txt', 'html', 'htm', 'css', 'js'].includes(fileExtension)) { + console.log('棰勮鏂囨湰鏂囦欢:', previewUrl) + window.open(previewUrl, '_blank') + return + } + + // Office鏂囨。鍜屽叾浠栨枃浠剁被鍨嬶紝灏濊瘯鍦ㄦ柊绐楀彛鎵撳紑 + try { + console.log('棰勮鍏朵粬鏂囦欢:', previewUrl) + window.open(previewUrl, '_blank') + } catch (error) { + console.error('棰勮澶辫触:', error) + ElMessage.error('棰勮澶辫触锛岃涓嬭浇鍚庢煡鐪�') } } + +// 鏂囦欢涓嬭浇 +const handleDownload = async (file: any) => { + if (!file.url) { + ElMessage.warning('鏂囦欢閾炬帴涓嶅瓨鍦�') + return + } + + console.log('寮�濮嬩笅杞芥枃浠�:', file.name, 'URL:', file.url) + + try { + // 濡傛灉鏂囦欢瀛樺偍鍦∕inIO锛屼娇鐢ㄥ悗绔洿鎺ヤ笅杞紸PI + if (file.url.includes('order-attachments')) { + console.log('浣跨敤MinIO涓嬭浇API') + + // 浣跨敤axios閫氳繃浠g悊璁块棶鍚庣API + const response = await createAxios({ + url: `/admin/file/download`, + method: 'GET', + responseType: 'blob', + params: { + fileName: file.url, + originalName: file.name + } + }) + + console.log('涓嬭浇鍝嶅簲:', response) + + // 鍒涘缓涓嬭浇閾炬帴 + const blob = new Blob([response as any]) + const downloadUrl = window.URL.createObjectURL(blob) + + console.log('鍒涘缓涓嬭浇閾炬帴:', downloadUrl) + + const link = document.createElement('a') + link.href = downloadUrl + link.download = file.name || 'download' + link.target = '_blank' + link.rel = 'noopener noreferrer' + + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + + // 娓呯悊URL瀵硅薄 + window.URL.revokeObjectURL(downloadUrl) + + ElMessage.success('鏂囦欢涓嬭浇鎴愬姛') + } else { + console.log('浣跨敤鐩存帴URL涓嬭浇') + // 鍏朵粬鎯呭喌鐩存帴浣跨敤鍘烾RL + const link = document.createElement('a') + link.href = file.url + link.download = file.name || 'download' + link.target = '_blank' + link.rel = 'noopener noreferrer' + + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + + ElMessage.success('寮�濮嬩笅杞芥枃浠�') + } + } catch (error) { + console.error('涓嬭浇澶辫触:', error) + ElMessage.error('涓嬭浇澶辫触锛岃閲嶈瘯') + } +} + + // 鐥囩粨涓庝慨澶嶈鏄庯細 // 1) Element Plus 鐨� el-table 瀛愬垪 width 鐧惧垎姣旀槸鐩稿浜庤〃鏍煎鍣ㄧ殑鍍忕礌瀹藉害璁$畻锛屼絾鍙湁鍦ㄨ〃鏍煎鍣ㄦ湁鏄庣‘瀹藉害鏃舵墠鐢熸晥銆� @@ -694,6 +1012,36 @@ text-align: left !important; } +/* 鏂囦欢鎿嶄綔鎸夐挳鏍峰紡 */ +.file-actions { + display: flex; + gap: 8px; + align-items: center; + justify-content: center; + + .preview-btn { + color: #409eff; + &:hover { + text-decoration: underline; + } + &:disabled { + color: #c0c4cc; + cursor: not-allowed; + } + } + + .download-btn { + color: #67c23a; + &:hover { + text-decoration: underline; + } + &:disabled { + color: #c0c4cc; + cursor: not-allowed; + } + } +} + /* 浜ゆ槗淇℃伅澶囨敞琛ㄦ牸鏍峰紡 */ .remark-table { width: 100%; @@ -701,8 +1049,9 @@ display: flex; align-items: center; gap: 10px; - .forever-checkbox { - margin-left: 10px; + .forever-text { + color: #409eff; + font-weight: 500; } } } -- Gitblit v1.8.0