From fca192d3c38c5dcfbb6ace8bc71d6078f6a079b2 Mon Sep 17 00:00:00 2001 From: 啊鑫 <t2856754968@163.com> Date: 星期日, 20 七月 2025 18:09:06 +0800 Subject: [PATCH] LLJ附件系统全面优化:多格式文件预览与APK兼容性 --- APK兼容性优化说明.md | 217 +++++++++ pages/QC/LLJ/Add.vue | 852 ++++++++++++++++++++++++++++++++++-- FTP文件操作接口文档-更新版.md | 296 ++++++++++++ store/index.js | 5 4 files changed, 1,310 insertions(+), 60 deletions(-) diff --git "a/APK\345\205\274\345\256\271\346\200\247\344\274\230\345\214\226\350\257\264\346\230\216.md" "b/APK\345\205\274\345\256\271\346\200\247\344\274\230\345\214\226\350\257\264\346\230\216.md" new file mode 100644 index 0000000..77c2e81 --- /dev/null +++ "b/APK\345\205\274\345\256\271\346\200\247\344\274\230\345\214\226\350\257\264\346\230\216.md" @@ -0,0 +1,217 @@ +# APK鍏煎鎬т紭鍖栬鏄� + +## 馃幆 姒傝堪 +閽堝UniApp椤圭洰鎵撳寘鎴怉ndroid APK鏃剁殑鍏煎鎬ч棶棰橈紝宸插疄鏂藉叏闈㈢殑浼樺寲鏂规锛岀‘淇濇墍鏈夊姛鑳藉湪APP鐜涓甯歌繍琛屻�� + +## 馃敡 宸茶В鍐崇殑鍏煎鎬ч棶棰� + +### 1. 鏂囦欢棰勮鍔熻兘鍏煎鎬� + +#### 闂鎻忚堪 +- H5鐜鍜孉PP鐜鐨勬枃浠跺姞杞芥満鍒朵笉鍚� +- 缃戠粶鍥剧墖鍦ˋPP涓彲鑳芥棤娉曠洿鎺ユ樉绀� +- 涓嶅悓鏂囦欢绫诲瀷闇�瑕佷笉鍚岀殑澶勭悊绛栫暐 + +#### 瑙e喅鏂规 +```javascript +// 鍥剧墖棰勮 - APP鐜鍏堜笅杞藉埌鏈湴 +// #ifdef APP-PLUS +uni.downloadFile({ + url: url, + success: (res) => { + // 浣跨敤鏈湴璺緞棰勮 + uni.navigateTo({ + url: `/pages/fileView/imageView?url=${encodeURIComponent(res.tempFilePath)}` + }); + } +}); +// #endif + +// H5鐜鐩存帴浣跨敤缃戠粶URL +// #ifdef H5 +uni.navigateTo({ + url: `/pages/fileView/imageView?url=${encodeURIComponent(url)}` +}); +// #endif +``` + +### 2. 鏂囦欢涓嬭浇鍔熻兘浼樺寲 + +#### 闂鎻忚堪 +- H5鐜浣跨敤blob涓嬭浇锛孉PP闇�瑕乽ni.downloadFile +- APP涓枃浠跺瓨鍌ㄨ矾寰勫拰鏉冮檺澶勭悊 +- 涓嬭浇杩涘害鏄剧ず鍜岀敤鎴蜂綋楠� + +#### 瑙e喅鏂规 +```javascript +// APP鐜浼樺寲 +// #ifdef APP-PLUS +const saveDir = plus.os.name === 'Android' ? + plus.io.convertLocalFileSystemURL('_downloads/') : + plus.io.convertLocalFileSystemURL('_documents/'); + +const downloadTask = uni.downloadFile({ + url: url, + filePath: `${saveDir}${fileName}`, // 鎸囧畾淇濆瓨璺緞 + success: (res) => { + // 鎻愪緵鎵撳紑鏂囦欢閫夐」 + uni.showModal({ + title: '涓嬭浇鎴愬姛', + confirmText: '鎵撳紑鏂囦欢', + success: (modalRes) => { + if (modalRes.confirm) { + plus.runtime.openFile(res.filePath); + } + } + }); + } +}); + +// 鏄剧ず涓嬭浇杩涘害 +downloadTask.onProgressUpdate((res) => { + const progress = Math.round(res.progress); + uni.showLoading({ title: `涓嬭浇涓� ${progress}%` }); +}); +// #endif +``` + +### 3. 缃戠粶璇锋眰鍏煎鎬� + +#### 闂鎻忚堪 +- CORS闂鍦ˋPP涓笉瀛樺湪锛屼絾鏈夊叾浠栭檺鍒� +- 璇锋眰澶村拰鍝嶅簲澶勭悊鍙兘涓嶅悓 +- 瓒呮椂鍜岄敊璇鐞嗘満鍒� + +#### 瑙e喅鏂规 +- **APP鐜**锛氭棤闇�澶勭悊CORS锛屼娇鐢ㄥ師鐢熺綉缁滆姹� +- **H5鐜**锛氫繚鐣機ORS澶勭悊鍜屽绉嶄笅杞介檷绾х瓥鐣� +- **缁熶竴閿欒澶勭悊**锛氭彁渚涘弸濂界殑閿欒鎻愮ず + +### 4. UI缁勪欢閫傞厤 + +#### 闂鎻忚堪 +- 寮圭獥鍦ㄤ笉鍚屽睆骞曞昂瀵镐笅鐨勬樉绀� +- CSS鏍峰紡鍦ˋPP涓殑娓叉煋宸紓 +- 瑙︽懜浜や簰鐨勪紭鍖� + +#### 瑙e喅鏂规 +```css +/* APP鐜涓撶敤鏍峰紡 */ +/* #ifdef APP-PLUS */ +.file-preview-popup { + width: 85vw; + max-height: 75vh; +} +.file-preview-content { + max-height: 350px; +} +/* #endif */ +``` + +## 馃摫 鏀寔鐨勬枃浠剁被鍨� + +### 瀹屽叏鏀寔棰勮 +- **鏂囨湰鏂囦欢**: txt, log, md, csv, json, xml +- **鍥剧墖鏂囦欢**: jpg, jpeg, png, gif, bmp, webp + +### 鍙嬪ソ鎻愮ず涓嬭浇 +- **Office鏂囨。**: doc, docx, xls, xlsx, ppt, pptx +- **PDF鏂囦欢**: pdf +- **鍏朵粬鏍煎紡**: 鏄剧ず涓嶆敮鎸佹彁绀猴紝鎻愪緵涓嬭浇閫夐」 + +## 馃敀 鏉冮檺鍜屽畨鍏� + +### Android鏉冮檺 +APP浼氳嚜鍔ㄧ敵璇蜂互涓嬫潈闄愶細 +- `WRITE_EXTERNAL_STORAGE`: 鏂囦欢鍐欏叆鏉冮檺 +- `INTERNET`: 缃戠粶璁块棶鏉冮檺 +- `ACCESS_NETWORK_STATE`: 缃戠粶鐘舵�佹娴� + +### 鏂囦欢瀛樺偍浣嶇疆 +- **Android**: `_downloads/` 鐩綍锛堢敤鎴峰彲璁块棶锛� +- **iOS**: `_documents/` 鐩綍锛堝簲鐢ㄦ矙鐩掞級 + +## 馃殌 鎬ц兘浼樺寲 + +### 涓嬭浇浼樺寲 +- 鏄剧ず瀹炴椂涓嬭浇杩涘害 +- 鑷姩閲嶈瘯鏈哄埗 +- 缃戠粶鐘舵�佹娴� +- 鏂囦欢澶у皬棰勬 + +### 鍐呭瓨绠$悊 +- 鍙婃椂閲婃斁涓存椂鏂囦欢 +- 鍥剧墖棰勮浣跨敤鏈湴缂撳瓨 +- 閬垮厤澶ф枃浠跺唴瀛樺崰鐢� + +### 鐢ㄦ埛浣撻獙 +- 鍔犺浇鐘舵�佸弽棣� +- 鍙嬪ソ鐨勯敊璇彁绀� +- 涓�閿墦寮�涓嬭浇鏂囦欢 +- 鍙栨秷涓嬭浇鍔熻兘 + +## 馃攳 娴嬭瘯寤鸿 + +### 璁惧鍏煎鎬ф祴璇� +1. **涓嶅悓Android鐗堟湰**: 5.0+ 鏀寔 +2. **涓嶅悓灞忓箷灏哄**: 4瀵竳7瀵稿钩鏉� +3. **涓嶅悓鍝佺墝PDA**: 纭繚纭欢鍔熻兘姝e父 + +### 鍔熻兘娴嬭瘯娓呭崟 +- [ ] 鏂囦欢棰勮锛堝悇绉嶆牸寮忥級 +- [ ] 鏂囦欢涓嬭浇锛堢綉缁�/绂荤嚎锛� +- [ ] 瀛樺偍鏉冮檺鐢宠 +- [ ] 澶ф枃浠跺鐞嗭紙>10MB锛� +- [ ] 缃戠粶涓柇鎭㈠ +- [ ] 寮圭獥鏄剧ず閫傞厤 + +### 鎬ц兘娴嬭瘯 +- [ ] 鍚姩閫熷害 +- [ ] 鍐呭瓨鍗犵敤 +- [ ] 鏂囦欢鎿嶄綔鍝嶅簲鏃堕棿 +- [ ] 鎵归噺涓嬭浇鎬ц兘 + +## 馃搵 閮ㄧ讲娉ㄦ剰浜嬮」 + +### manifest.json 閰嶇疆 +```json +{ + "app-plus": { + "modules": { + "FileSystem": {} + }, + "permissions": { + "鍐欏叆绯荤粺瀛樺偍": { + "request": "always" + } + } + } +} +``` + +### 鎵撳寘閰嶇疆 +- 鍚敤鏂囦欢绯荤粺妯″潡 +- 閰嶇疆瀛樺偍鏉冮檺 +- 璁剧疆缃戠粶瀹夊叏绛栫暐 +- 浼樺寲鍖呭ぇ灏� + +## 馃悰 宸茬煡闄愬埗 + +1. **澶ф枃浠堕瑙�**: 瓒呰繃50MB鐨勬枃浠跺缓璁洿鎺ヤ笅杞� +2. **缃戠粶渚濊禆**: 棰勮鍔熻兘闇�瑕佺ǔ瀹氱殑缃戠粶杩炴帴 +3. **瀛樺偍绌洪棿**: 涓嬭浇鏂囦欢浼氬崰鐢ㄨ澶囧瓨鍌ㄧ┖闂� +4. **绯荤粺搴旂敤**: 鏌愪簺鏂囦欢绫诲瀷闇�瑕佸畨瑁呭搴旂殑闃呰鍣� + +## 馃摓 鎶�鏈敮鎸� + +濡傞亣鍒板吋瀹规�ч棶棰橈細 +1. 妫�鏌ヨ澶嘇ndroid鐗堟湰锛堝缓璁�5.0+锛� +2. 纭瀛樺偍鏉冮檺宸叉巿浜� +3. 娴嬭瘯缃戠粶杩炴帴鐘跺喌 +4. 鏌ョ湅鎺у埗鍙伴敊璇棩蹇� + +--- + +**鏂囨。鐗堟湰**: v1.0 +**鏈�鍚庢洿鏂�**: 2025-07-20 +**閫傜敤鐗堟湰**: UniApp v2.0.2+ \ No newline at end of file diff --git "a/FTP\346\226\207\344\273\266\346\223\215\344\275\234\346\216\245\345\217\243\346\226\207\346\241\243-\346\233\264\346\226\260\347\211\210.md" "b/FTP\346\226\207\344\273\266\346\223\215\344\275\234\346\216\245\345\217\243\346\226\207\346\241\243-\346\233\264\346\226\260\347\211\210.md" new file mode 100644 index 0000000..1e5bb22 --- /dev/null +++ "b/FTP\346\226\207\344\273\266\346\223\215\344\275\234\346\216\245\345\217\243\346\226\207\346\241\243-\346\233\264\346\226\260\347\211\210.md" @@ -0,0 +1,296 @@ +# 闄勪欢绠$悊绯荤粺 - FTP鏂囦欢鎿嶄綔鎺ュ彛鏂囨。 (鏇存柊鐗�) + +## 馃毃 閲嶈鏇存柊锛欳ORS璺ㄥ煙闂瑙e喅鏂规 + +### 闂鎻忚堪 +鍦℉5鐜涓娇鐢� `DownloadFtpFile` 鎺ュ彛鏃跺嚭鐜颁互涓嬮敊璇細 +``` +Refused to get unsafe header "content-disposition" +``` + +### 鍘熷洜鍒嗘瀽 +杩欐槸鐢变簬娴忚鍣ㄧ殑CORS锛堣法鍩熻祫婧愬叡浜級瀹夊叏绛栫暐瀵艰嚧鐨勶紝娴忚鍣ㄩ樆姝簡鍓嶇璁块棶鏌愪簺HTTP鍝嶅簲澶淬�� + +### 瑙e喅鏂规 + +#### 鍚庣CORS閰嶇疆锛堝繀椤伙級 +鍚庣鎺ュ彛蹇呴』璁剧疆浠ヤ笅CORS鍝嶅簲澶达細 + +```http +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, POST, OPTIONS +Access-Control-Allow-Headers: Content-Type, Authorization +Access-Control-Expose-Headers: Content-Disposition, Content-Length, Content-Type +``` + +**鍏抽敭鐐�**: `Access-Control-Expose-Headers` 蹇呴』鍖呭惈 `Content-Disposition`锛屽惁鍒欏墠绔棤娉曡鍙栨枃浠跺悕淇℃伅銆� + +#### 鍓嶇澶氱幆澧冨吋瀹癸紙宸插疄鐜帮級 +鍓嶇浠g爜宸叉洿鏂颁负澶氱幆澧冨吋瀹癸細 + +1. **H5鐜**: 浣跨敤澶氱涓嬭浇鏂瑰紡鐨勯檷绾х瓥鐣� + - 鏂规硶1: `<a>` 鏍囩涓嬭浇 + - 鏂规硶2: `window.open` 涓嬭浇 + - 鏂规硶3: `fetch` + `blob` 涓嬭浇 + +2. **APP鐜**: 浣跨敤 `uni.downloadFile` +3. **灏忕▼搴忕幆澧�**: 浣跨敤 `uni.downloadFile` + +--- + +## 鍩虹淇℃伅 +- **鏈嶅姟鍣ㄥ湴鍧�**: `http://36.26.21.214:10054/api` +- **FTP鏈嶅姟鍣�**: `ftp://36.26.21.214` +- **妯″潡**: LLJ (鏉ユ枡妫�楠�) + +--- + +## 1. 鑾峰彇闄勪欢鍒楄〃 + +### 鎺ュ彛淇℃伅 +- **URL**: `/LLJ/getAttachments` +- **鏂规硶**: `POST` +- **鐢ㄩ��**: 鑾峰彇鎸囧畾妫�楠屽崟鐨勯檮浠跺垪琛� + +### 璇锋眰鍙傛暟 +```json +{ + "releaseNo": "妫�楠屽崟鍙�" +} +``` + +### 鍝嶅簲鏍煎紡 +```json +{ + "status": 0, + "message": "鎴愬姛", + "data": { + "tbBillList": [ + { + "id": 123456, + "itemNo": "鐗╂枡缂栧彿", + "fattach": "闄勪欢鏂囦欢鍚�.pdf", + "ftype": "鏂囦欢绫诲瀷", + "fversion": "鐗堟湰鍙�", + "fdate": "鍙楁帶鏃ユ湡", + "createBy": "涓婁紶浜�", + "createDate": "涓婁紶鏃堕棿" + } + ] + } +} +``` + +--- + +## 2. 棰勮FTP鏂囦欢 + +### 鎺ュ彛淇℃伅 +- **URL**: `/LLJ/PreviewFtpFile` +- **鏂规硶**: `GET` +- **鐢ㄩ��**: 鑾峰彇FTP鏈嶅姟鍣ㄤ笂鏂囦欢鐨勯瑙堟祦 + +### 璇锋眰鍙傛暟 +| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 | +|--------|------|------|------| +| itemNo | string | 鏄� | 鐗╂枡缂栧彿 | +| fileName | string | 鏄� | 鏂囦欢鍚嶏紙闇�URL缂栫爜锛� | +| ftpServer | string | 鏄� | FTP鏈嶅姟鍣ㄥ湴鍧� `ftp://36.26.21.214` | + +### CORS閰嶇疆瑕佹眰 +```http +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, OPTIONS +Access-Control-Allow-Headers: Content-Type +Access-Control-Expose-Headers: Content-Type, Content-Length +``` + +### 鏀寔鐨勬枃浠剁被鍨� +- **PDF鏂囦欢**: `pdf` +- **鍥剧墖鏂囦欢**: `jpg`, `jpeg`, `png`, `gif`, `bmp`, `webp` +- **鏂囨湰鏂囦欢**: `txt`, `log`, `md`, `csv` +- **Office鏂囨。**: `doc`, `docx`, `xls`, `xlsx`, `ppt`, `pptx` + +--- + +## 3. 涓嬭浇FTP鏂囦欢 猸� 閲嶇偣鏇存柊 + +### 鎺ュ彛淇℃伅 +- **URL**: `/LLJ/DownloadFtpFile` +- **鏂规硶**: `GET` +- **鐢ㄩ��**: 浠嶧TP鏈嶅姟鍣ㄤ笅杞芥枃浠� + +### 璇锋眰鍙傛暟 +| 鍙傛暟鍚� | 绫诲瀷 | 蹇呭~ | 璇存槑 | +|--------|------|------|------| +| itemNo | string | 鏄� | 鐗╂枡缂栧彿 | +| fileName | string | 鏄� | 鏂囦欢鍚嶏紙闇�URL缂栫爜锛� | +| ftpServer | string | 鏄� | FTP鏈嶅姟鍣ㄥ湴鍧� `ftp://36.26.21.214` | + +### 鈿狅笍 鍏抽敭CORS閰嶇疆 +```http +Access-Control-Allow-Origin: * +Access-Control-Allow-Methods: GET, OPTIONS +Access-Control-Allow-Headers: Content-Type, Authorization +Access-Control-Expose-Headers: Content-Disposition, Content-Length, Content-Type +``` + +### 鍝嶅簲澶磋姹� +```http +Content-Type: application/octet-stream (鎴栧叿浣撶殑MIME绫诲瀷) +Content-Disposition: attachment; filename="鏂囦欢鍚�.pdf" +Content-Length: 鏂囦欢澶у皬 +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: Content-Disposition, Content-Length, Content-Type +``` + +### 鍓嶇澶勭悊绛栫暐 +```javascript +// H5鐜锛氬绉嶄笅杞芥柟寮� +1. <a> 鏍囩涓嬭浇 (棣栭��) +2. window.open 涓嬭浇 (澶囬��) +3. fetch + blob 涓嬭浇 (鍏滃簳) + +// APP/灏忕▼搴忕幆澧冿細 +uni.downloadFile (鍘熺敓涓嬭浇) +``` + +--- + +## 4. 瀹炵幇寤鸿 + +### 鍚庣CORS涓棿浠堕厤缃ず渚� + +#### .NET Core 绀轰緥 +```csharp +public void ConfigureServices(IServiceCollection services) +{ + services.AddCors(options => + { + options.AddPolicy("AllowAll", + builder => + { + builder + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader() + .WithExposedHeaders("Content-Disposition", "Content-Length", "Content-Type"); + }); + }); +} + +public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +{ + app.UseCors("AllowAll"); +} +``` + +#### Express.js 绀轰緥 +```javascript +app.use((req, res, next) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + res.header('Access-Control-Expose-Headers', 'Content-Disposition, Content-Length, Content-Type'); + next(); +}); +``` + +### 鏂囦欢涓嬭浇鍝嶅簲绀轰緥 +```http +HTTP/1.1 200 OK +Content-Type: application/pdf +Content-Disposition: attachment; filename="娴嬭瘯鏂囨。.pdf" +Content-Length: 1024000 +Access-Control-Allow-Origin: * +Access-Control-Expose-Headers: Content-Disposition, Content-Length, Content-Type + +[鏂囦欢浜岃繘鍒舵暟鎹甝 +``` + +--- + +## 5. 鏁呴殰鎺掗櫎 + +### 甯歌闂鍙婅В鍐虫柟妗� + +#### 闂1: "Refused to get unsafe header" +**鍘熷洜**: 鍚庣鏈缃� `Access-Control-Expose-Headers` +**瑙e喅**: 娣诲姞 `Access-Control-Expose-Headers: Content-Disposition, Content-Length, Content-Type` + +#### 闂2: CORS棰勬璇锋眰澶辫触 +**鍘熷洜**: 鍚庣鏈鐞� OPTIONS 璇锋眰 +**瑙e喅**: 娣诲姞 OPTIONS 鏂规硶鏀寔鍜岀浉搴旂殑CORS澶� + +#### 闂3: 鏂囦欢涓嬭浇浣嗘枃浠跺悕涔辩爜 +**鍘熷洜**: Content-Disposition 涓殑鏂囦欢鍚嶇紪鐮侀棶棰� +**瑙e喅**: 浣跨敤 UTF-8 缂栫爜鎴� RFC 5987 鏍煎紡 +```http +Content-Disposition: attachment; filename*=UTF-8''%E6%B5%8B%E8%AF%95%E6%96%87%E6%A1%A3.pdf +``` + +#### 闂4: 澶ф枃浠朵笅杞借秴鏃� +**鍘熷洜**: 鏈嶅姟鍣ㄦ垨缃戠粶瓒呮椂 +**瑙e喅**: +- 澧炲姞鏈嶅姟鍣ㄨ秴鏃惰缃� +- 瀹炵幇鏂偣缁紶 +- 鎻愪緵鍒嗙墖涓嬭浇 + +--- + +## 6. 娴嬭瘯鏂规 + +### 娴嬭瘯鐜 +1. **H5鐜**: Chrome, Safari, Firefox +2. **APP鐜**: Android, iOS 鍘熺敓搴旂敤 +3. **灏忕▼搴忕幆澧�**: 寰俊灏忕▼搴� + +### 娴嬭瘯鐢ㄤ緥 +```javascript +// 娴嬭瘯CORS閰嶇疆 +fetch('http://36.26.21.214:10054/api/LLJ/DownloadFtpFile?itemNo=TEST&fileName=test.pdf&ftpServer=ftp%3A//36.26.21.214', { + method: 'GET' +}) +.then(response => { + console.log('Content-Disposition:', response.headers.get('Content-Disposition')); + // 搴旇鑳芥甯歌幏鍙栧埌鏂囦欢鍚� +}) +.catch(error => { + console.error('CORS Error:', error); +}); +``` + +--- + +## 7. 鐩戞帶涓庢棩蹇� + +### 寤鸿鐩戞帶鎸囨爣 +- 涓嬭浇鎴愬姛鐜� +- 涓嬭浇鑰楁椂 +- CORS閿欒棰戠巼 +- 鏂囦欢涓嶅瓨鍦ㄩ敊璇鐜� + +### 鏃ュ織璁板綍寤鸿 +```javascript +// 璁板綍涓嬭浇璇锋眰 +{ + "timestamp": "2025-07-20T10:00:00Z", + "method": "DownloadFtpFile", + "itemNo": "ABC123", + "fileName": "test.pdf", + "userAgent": "Mozilla/5.0...", + "success": true, + "errorCode": null, + "responseTime": 1500 +} +``` + +--- + +**鏂囨。鐗堟湰**: v2.0 (CORS鏇存柊鐗�) +**鏈�鍚庢洿鏂�**: 2025-07-20 +**鏇存柊鍐呭**: +- 鏂板CORS璺ㄥ煙闂瑙e喅鏂规 +- 鏇存柊鍓嶇澶氱幆澧冧笅杞界瓥鐣� +- 娣诲姞鍚庣CORS閰嶇疆绀轰緥 +- 瀹屽杽鏁呴殰鎺掗櫎鎸囧崡 \ No newline at end of file diff --git a/pages/QC/LLJ/Add.vue b/pages/QC/LLJ/Add.vue index 04f0623..52ddd2a 100644 --- a/pages/QC/LLJ/Add.vue +++ b/pages/QC/LLJ/Add.vue @@ -103,12 +103,6 @@ - <!-- 鎿嶄綔鎸夐挳鍖� --> - <view class="action-buttons" v-if="this.current"> - <button class="secondary-btn" @click="handleEmergencyRelease">绱ф�ユ斁琛�</button> - <button class="secondary-btn" @click="handleWithdraw">鎾ゅ洖</button> - <button class="secondary-btn" @click="getInspectionItems">鑾峰彇妫�楠岄」鐩�</button> - </view> @@ -147,14 +141,22 @@ </table> </view> - <!-- 鎿嶄綔鎸夐挳鍖� --> - <view class="action-buttons"> - <button class="secondary-btn" @click="addDestruction" v-if="this.current">鐮村潖瀹為獙</button> - <button class="secondary-btn" @click="uploadImages">涓婁紶/鏌ョ湅鍥剧墖</button> - <button class="secondary-btn" @click="fetchDrawingNumber">璋冨彇PLM鍥剧焊</button> - <button class="secondary-btn" @click="viewAttachmentInfo">鏌ョ湅闄勪欢淇℃伅</button> - <button class="secondary-btn" @click="addDefectDescription" v-if="this.current">娣诲姞涓嶈壇鎻忚堪</button> - <button class="primary-btn" @click="submitInspection" v-if="this.current">妫�楠屾彁浜�</button> + <!-- 椤甸潰鍐呭鍖哄煙 --> + <view class="content-wrapper"> + <!-- 涓哄簳閮ㄦ寜閽暀鍑虹┖闂� --> + </view> + + <!-- 鍥哄畾鍦ㄥ簳閮ㄧ殑鎿嶄綔鎸夐挳鍖� --> + <view class="fixed-action-buttons"> + <button class="action-btn" @click="handleEmergencyRelease" v-if="this.current">绱ф�ユ斁琛�</button> + <button class="action-btn" @click="handleWithdraw" v-if="this.current">鎾ゅ洖</button> + <button class="action-btn" @click="getInspectionItems" v-if="this.current">鑾峰彇妫�楠岄」鐩�</button> + <button class="action-btn" @click="addDestruction" v-if="this.current">鐮村潖瀹為獙</button> + <button class="action-btn" @click="uploadImages">涓婁紶/鏌ョ湅鍥剧墖</button> + <button class="action-btn" @click="fetchDrawingNumber">璋冨彇PLM鍥剧焊</button> + <button class="action-btn" @click="viewAttachmentInfo">鏌ョ湅闄勪欢淇℃伅</button> + <button class="action-btn" @click="addDefectDescription" v-if="this.current">娣诲姞涓嶈壇鎻忚堪</button> + <button class="action-btn primary" @click="submitInspection" v-if="this.current">妫�楠屾彁浜�</button> </view> <view v-if="remarksPopup" class="overlay"> <view class="popup"> @@ -189,8 +191,8 @@ <view class="barcode"> <u-modal :show="drawingShow" title="鍥剧焊鏄庣粏" @confirm="drawingConfirm" @cancel="drawingCancel" - showCancelButton> - <uni-table border stripe emptyText="鏆傛棤鏇村鏁版嵁" style="margin-left: 5px;margin-right: 5px;height: 500px;"> + showCancelButton :z-index="1000"> + <uni-table border stripe emptyText="鏆傛棤鏇村鏁版嵁" style="margin-left: 5px;margin-right: 5px;height: 400px;max-height: 60vh;overflow-y: auto;"> <uni-tr> <uni-th align="center">鐩稿叧鏂囨。</uni-th> <uni-th align="center" width="90">鏈夋棤鍏宠仈PDF鏂囦欢</uni-th> @@ -227,19 +229,16 @@ <div class="attachment-detail-row"><span class="attachment-label">鍙楁帶鏃ユ湡锛�</span><span>{{ selectedAttachment.fdate }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">涓婁紶浜猴細</span><span>{{ selectedAttachment.createBy }}</span></div> <div class="attachment-detail-row"><span class="attachment-label">涓婁紶鏃堕棿锛�</span><span>{{ selectedAttachment.createDate }}</span></div> - <div v-if="isPreviewable(selectedAttachment.fattach)" class="attachment-preview-area"> - <div v-if="['pdf','jpg','jpeg','png','gif'].includes(selectedAttachment.fattach.trim().split('.').pop().toLowerCase())"> - <iframe :src="getAttachmentUrl(selectedAttachment)" style="width:100%;height:320px;border-radius:10px;background:#f8fafc;" frameborder="0"></iframe> - </div> - <div v-else-if="['txt'].includes(selectedAttachment.fattach.trim().split('.').pop().toLowerCase())"> - <iframe :src="getAttachmentUrl(selectedAttachment)" style="width:100%;height:320px;border-radius:10px;background:#f8fafc;" frameborder="0"></iframe> - </div> - <div v-else-if="['doc','docx','xls','xlsx'].includes(selectedAttachment.fattach.trim().split('.').pop().toLowerCase())"> - <iframe :src="'https://view.officeapps.live.com/op/view.aspx?src=' + encodeURIComponent(getAttachmentUrl(selectedAttachment))" style="width:100%;height:320px;border-radius:10px;background:#f8fafc;" frameborder="0"></iframe> - </div> - </div> - <div v-else class="attachment-download-area"> - <button class="attachment-download-link" @click="downloadAttachment(selectedAttachment)">涓嬭浇闄勪欢</button> + <div class="attachment-actions-detail"> + <button class="attachment-action-btn preview-btn" + @click="previewFtpFile(selectedAttachment)" + v-if="isPreviewable(selectedAttachment.fattach)"> + 馃攳 鍦ㄧ嚎棰勮 + </button> + <button class="attachment-action-btn download-btn" + @click="downloadAttachment(selectedAttachment)"> + 馃摜 涓嬭浇鏂囦欢 + </button> </div> </div> <div v-else class="attachment-detail-empty">鏆傛棤闄勪欢淇℃伅</div> @@ -254,16 +253,58 @@ <div v-else-if="attachments.length === 0">鏆傛棤闄勪欢</div> <ul class="attachment-list" v-else> <li v-for="item in attachments" :key="item.id"> - <span class="attachment-name" @click="showAttachmentDetailDialog(item)"> - {{ item.fattach }} - </span> + <div class="attachment-info"> + <span class="attachment-name" @click="showAttachmentDetailDialog(item)"> + {{ item.fattach }} + </span> + <div class="attachment-meta"> + <span class="attachment-type">{{ item.ftype || '鏈煡绫诲瀷' }}</span> + </div> + </div> <div class="attachment-actions"> <button class="secondary-btn" @click="showAttachmentDetailDialog(item)">璇︽儏</button> + <button class="secondary-btn preview-btn" @click="previewFtpFile(item)" + v-if="isPreviewable(item.fattach)">棰勮</button> <button class="secondary-btn" @click="downloadAttachment(item)">涓嬭浇</button> </div> </li> </ul> <button class="attachment-popup-close" @click="closeAttachmentPopup">鍏抽棴</button> + </view> + </view> + + <!-- 鏂囦欢棰勮寮圭獥 --> + <view v-if="showFilePreviewPopup" class="overlay"> + <view class="popup file-preview-popup"> + <h3 class="file-preview-title">{{ previewTitle }}</h3> + <div class="file-preview-divider"></div> + <div class="file-preview-content"> + <!-- 鏂囨湰鍐呭棰勮 --> + <pre v-if="previewType === 'text'">{{ previewContent }}</pre> + + <!-- 鍥剧墖鍐呭棰勮 --> + <view v-else-if="previewType === 'image'" class="image-preview-container"> + <image :src="previewContent" mode="widthFix" style="width: 100%; max-height: 400px;"></image> + </view> + + <!-- Excel 绛� Office 鏂囦欢鎻愮ず --> + <view v-else-if="previewType === 'excel'" class="unsupported-preview"> + <view class="unsupported-icon">馃搳</view> + <view class="unsupported-text">Excel 鏂囦欢鏆備笉鏀寔鍦ㄧ嚎棰勮</view> + <view class="unsupported-hint">璇风偣鍑讳笅杞芥寜閽幏鍙栧畬鏁存枃浠�</view> + </view> + + <!-- 涓嶆敮鎸佺殑鏂囦欢绫诲瀷 --> + <view v-else class="unsupported-preview"> + <view class="unsupported-icon">馃搫</view> + <view class="unsupported-text">姝ゆ枃浠舵牸寮忔殏涓嶆敮鎸侀瑙�</view> + <view class="unsupported-hint">璇风偣鍑讳笅杞芥寜閽幏鍙栧畬鏁存枃浠�</view> + </view> + </div> + <div class="file-preview-actions"> + <button v-if="previewType !== 'text'" class="file-preview-btn download-btn" @click="downloadPreviewFile">馃摜 涓嬭浇鏂囦欢</button> + <button class="file-preview-btn close-btn" @click="closeFilePreview">鍏抽棴</button> + </div> </view> </view> </view> @@ -325,6 +366,11 @@ attachmentsLoading: false, selectedAttachment: null, showAttachmentDetail: false, + showFilePreviewPopup: false, + previewContent: '', + previewTitle: '', + previewItemNo: '', + previewType: '', // 'text', 'image', 'excel', 'unsupported' } }, @@ -1286,6 +1332,11 @@ this.attachmentsLoading = false; if (res.status === 0) { this.attachments = res.data.tbBillList; + // 涓烘瘡涓檮浠惰缃粯璁ゅ彲鐢ㄧ姸鎬� + this.attachments.forEach((item, index) => { + this.$set(item, 'ftpAvailable', true); // 榛樿璁や负鏂囦欢鍙敤 + this.$set(item, 'checking', false); + }); } else if (res.status === 1 && res.message === "璇ユ楠屽崟鏈笂浼犻檮浠朵俊鎭紒") { uni.showToast({ title: res.message, icon: "none" }); } else { @@ -1297,10 +1348,10 @@ this.showAttachmentPopup = false; }, getAttachmentUrl(item) { - const baseUrl = "http://192.168.1.22:10054"; // 鍘婚櫎鎵�鏈夌┖鐧藉瓧绗︼紙鍖呮嫭涓嫳鏂囩┖鏍笺�佸埗琛ㄧ绛夛級 - let fileName = item.fattach.replace(/[\s\u3000]+/g, '').trim(); - return baseUrl + "/api/LLJ/DownloadAttachment?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName); + let fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); + // 缁熶竴浣跨敤FTP涓嬭浇鎺ュ彛锛屽寘鍚獸TP鏈嶅姟鍣ㄥ湴鍧� + return this.$store.state.serverInfo.serverAPI + "/LLJ/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); }, showAttachmentDetailDialog(item) { console.log('鏌ョ湅璇︽儏', item); @@ -1319,7 +1370,13 @@ const ext = filename.trim().split('.').pop().toLowerCase(); // 鏀寔鍦ㄧ嚎棰勮鐨勬枃浠剁被鍨� return [ - 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'txt', 'doc', 'docx', 'xls', 'xlsx' + 'pdf', // PDF鏂囦欢 + 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', // 鍥剧墖鏂囦欢 + 'txt', 'log', 'md', // 鏂囨湰鏂囦欢 + 'doc', 'docx', // Word鏂囨。 + 'xls', 'xlsx', // Excel琛ㄦ牸 + 'ppt', 'pptx', // PowerPoint婕旂ず鏂囩 + 'csv' // CSV鏂囦欢 ].includes(ext); }, // 澶勭悊闄勪欢涓嬭浇閿欒 @@ -1330,32 +1387,474 @@ showCancel: false }); }, - downloadAttachment(item) { - const baseUrl = "http://192.168.1.22:10054"; - // 鍘婚櫎鎵�鏈夌┖鏍笺�佸叏瑙掔┖鏍笺�佸洖杞︺�佹崲琛� + // 棰勮FTP鏂囦欢 + previewFtpFile(item) { const fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); - const url = baseUrl + "/api/Llj/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName); - uni.downloadFile({ + const fileExt = fileName.split('.').pop().toLowerCase(); + + // 妫�鏌ユ枃浠剁被鍨嬫槸鍚︽敮鎸侀瑙� + if (!this.isPreviewable(fileName)) { + uni.showModal({ + title: '涓嶆敮鎸侀瑙�', + content: '璇ユ枃浠剁被鍨嬩笉鏀寔鍦ㄧ嚎棰勮锛岃涓嬭浇鍚庢煡鐪�', + showCancel: false + }); + return; + } + + const previewUrl = this.$store.state.serverInfo.serverAPI + "/LLJ/PreviewFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); + + // 鏍规嵁鏂囦欢绫诲瀷杩涜涓嶅悓鐨勯瑙堝鐞� + if (['pdf'].includes(fileExt)) { + this.previewPdfFile(previewUrl, fileName); + } else if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(fileExt)) { + this.previewImageFile(previewUrl, fileName); + } else if (['txt'].includes(fileExt)) { + this.previewTextFile(previewUrl, fileName); + } else if (['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'].includes(fileExt)) { + this.previewOfficeFile(previewUrl, fileName); + } else { + // 灏濊瘯閫氱敤棰勮 + this.previewGenericFile(previewUrl, fileName); + } + }, + + // 棰勮PDF鏂囦欢 + previewPdfFile(url, fileName) { + // 鍏堜笅杞絇DF鏂囦欢锛岃浆涓篵ase64鍚庨瑙� + uni.request({ url: url, + method: 'GET', + responseType: 'arraybuffer', success: (res) => { if (res.statusCode === 200) { - if (typeof plus !== 'undefined' && plus.runtime && plus.runtime.openFile) { - plus.runtime.openFile({ path: res.tempFilePath }, () => { - uni.showToast({ title: '鎵撳紑鎴愬姛', icon: 'success' }); - }, (e) => { - uni.showModal({ title: '鎻愮ず', content: '鏂囦欢涓嬭浇鎴愬姛锛屼絾鏃犳硶鑷姩鎵撳紑銆傝鍦ㄦ枃浠剁鐞嗕腑鎵嬪姩鏌ユ壘骞舵墦寮�銆�', showCancel: false }); - }); - } else { - uni.showModal({ title: '鎻愮ず', content: '鏂囦欢涓嬭浇鎴愬姛锛屼絾褰撳墠鐜鏃犳硶鑷姩鎵撳紑銆傝鍦ㄦ枃浠剁鐞嗕腑鎵嬪姩鏌ユ壘骞舵墦寮�銆�', showCancel: false }); - } + const base64Data = uni.arrayBufferToBase64(res.data); + // 瀛樺偍鍒板叏灞�鍙橀噺 + getApp().globalData.tempPDF = base64Data; + uni.navigateTo({ + url: `/pages/fileView/pdfView` + }); } else { - uni.showModal({ title: '涓嬭浇澶辫触', content: `涓嬭浇澶辫触锛岀姸鎬佺爜锛�${res.statusCode}`, showCancel: false }); + this.handlePreviewError(res.statusCode, fileName); } }, fail: (error) => { - uni.showModal({ title: '涓嬭浇澶辫触', content: `涓嬭浇澶辫触锛岃妫�鏌ョ綉缁滆繛鎺ャ��${error.errMsg}`, showCancel: false }); + this.handlePreviewError(0, fileName, error.errMsg); } }); + }, + + // 棰勮鍥剧墖鏂囦欢 + previewImageFile(url, fileName) { + // #ifdef APP-PLUS + // APP鐜锛氬厛涓嬭浇鍒版湰鍦板啀棰勮锛岄伩鍏嶇綉缁滃浘鐗囧姞杞介棶棰� + uni.showLoading({ title: '鍔犺浇鍥剧墖...' }); + uni.downloadFile({ + url: url, + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + // 浣跨敤鏈湴涓存椂璺緞 + uni.navigateTo({ + url: `/pages/fileView/imageView?url=${encodeURIComponent(res.tempFilePath)}` + }); + } else { + this.handlePreviewError(res.statusCode, fileName); + } + }, + fail: (error) => { + uni.hideLoading(); + this.handlePreviewError(0, fileName, error.errMsg); + } + }); + // #endif + + // #ifdef H5 || MP + // H5鍜屽皬绋嬪簭锛氱洿鎺ヤ娇鐢ㄧ綉缁淯RL + uni.navigateTo({ + url: `/pages/fileView/imageView?url=${encodeURIComponent(url)}` + }); + // #endif + }, + + // 棰勮鏂囨湰鏂囦欢 + previewTextFile(url, fileName) { + // 鏂囨湰鏂囦欢鐩存帴鏄剧ず鍦ㄥ脊绐椾腑 + uni.showLoading({ title: '鍔犺浇鏂囦欢鍐呭...' }); + uni.request({ + url: url, + method: 'GET', + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + const fileType = this.getFileType(fileName); + + if (fileType === 'text') { + // 鏂囨湰鏂囦欢锛氭樉绀哄唴瀹� + this.showFilePreview(res.data, fileName); + } else if (fileType === 'image') { + // 鍥剧墖鏂囦欢锛氭樉绀哄浘鐗嘦RL + this.showFilePreview(url, fileName); + } else { + // 鍏朵粬鏂囦欢绫诲瀷锛氭樉绀烘彁绀轰俊鎭� + this.showFilePreview('', fileName); + } + } else { + this.handlePreviewError(res.statusCode, fileName); + } + }, + fail: (error) => { + uni.hideLoading(); + this.handlePreviewError(0, fileName, error.errMsg); + } + }); + }, + + // 妫�娴嬫枃浠剁被鍨� + getFileType(fileName) { + const fileExt = fileName.split('.').pop().toLowerCase(); + + if (['txt', 'log', 'md', 'csv', 'json', 'xml'].includes(fileExt)) { + return 'text'; + } else if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExt)) { + return 'image'; + } else if (['xls', 'xlsx', 'doc', 'docx', 'ppt', 'pptx'].includes(fileExt)) { + return 'excel'; + } else { + return 'unsupported'; + } + }, + + // 鏄剧ず鏂囦欢棰勮寮圭獥 + showFilePreview(content, fileName) { + this.previewContent = content; + this.previewTitle = fileName; + this.previewItemNo = this.selectedAttachment?.itemNo || ''; + this.previewType = this.getFileType(fileName); + this.showFilePreviewPopup = true; + }, + + // 鍏抽棴鏂囦欢棰勮寮圭獥 + closeFilePreview() { + this.showFilePreviewPopup = false; + this.previewContent = ''; + this.previewTitle = ''; + this.previewItemNo = ''; + this.previewType = ''; + }, + + // 涓嬭浇棰勮鏂囦欢 + downloadPreviewFile() { + const item = { fattach: this.previewTitle, itemNo: this.previewItemNo }; + this.downloadAttachment(item); + this.closeFilePreview(); + }, + + // 棰勮Office鏂囦欢 + previewOfficeFile(url, fileName) { + // 鍏堟鏌xcel鏂囦欢锛屼娇鐢ㄤ笓闂ㄧ殑Excel棰勮椤甸潰 + const fileExt = fileName.split('.').pop().toLowerCase(); + if (['xls', 'xlsx'].includes(fileExt)) { + // Excel鏂囦欢棰勮 + uni.request({ + url: url, + method: 'GET', + responseType: 'arraybuffer', + success: (res) => { + if (res.statusCode === 200) { + const base64Data = uni.arrayBufferToBase64(res.data); + // 瀛樺偍 Base64 鏁版嵁鍒版湰鍦板瓨鍌� + uni.setStorageSync('excelBase64Data', base64Data); + uni.navigateTo({ + url: `/pages/fileView/excelView` + }); + } else { + this.handlePreviewError(res.statusCode, fileName); + } + }, + fail: (error) => { + this.handlePreviewError(0, fileName, error.errMsg); + } + }); + } else if (['doc', 'docx'].includes(fileExt)) { + // Word鏂囦欢锛屽皾璇曚娇鐢╓ord棰勮椤甸潰鎴栬�呭井杞湪绾块瑙� + try { + const officePreviewUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}`; + // 濡傛灉鏈墂ebView椤甸潰锛屼娇鐢╳ebView棰勮 + this.previewGenericFile(officePreviewUrl, fileName); + } catch (error) { + this.handlePreviewError(0, fileName, '涓嶆敮鎸佹Office鏂囦欢绫诲瀷鐨勯瑙�'); + } + } else { + // 鍏朵粬Office鏂囦欢锛屼娇鐢ㄥ井杞湪绾块瑙堟湇鍔� + const officePreviewUrl = `https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}`; + this.previewGenericFile(officePreviewUrl, fileName); + } + }, + + // 閫氱敤鏂囦欢棰勮 + previewGenericFile(url, fileName) { + // 鐢变簬娌℃湁閫氱敤鐨剋ebView椤甸潰锛屾樉绀烘彁绀哄苟鎻愪緵涓嬭浇 + uni.showModal({ + title: '鏂囦欢棰勮', + content: `鏂囦欢 "${fileName}" 闇�瑕佷笅杞藉悗鏌ョ湅锛屾槸鍚︾珛鍗充笅杞斤紵`, + showCancel: true, + confirmText: '涓嬭浇', + cancelText: '鍙栨秷', + success: (res) => { + if (res.confirm) { + const item = { fattach: fileName, itemNo: this.selectedAttachment.itemNo }; + this.downloadAttachment(item); + } + } + }); + }, + + // 澶勭悊棰勮閿欒 + handlePreviewError(statusCode, fileName, errorMsg = '') { + let message = ''; + if (statusCode === 404) { + message = `鏂囦欢 ${fileName} 鍦‵TP鏈嶅姟鍣ㄤ笂涓嶅瓨鍦╜; + } else if (statusCode === 0) { + message = `棰勮澶辫触锛�${errorMsg}`; + } else { + message = `棰勮澶辫触锛岀姸鎬佺爜锛�${statusCode}`; + } + + uni.showModal({ + title: '棰勮澶辫触', + content: message, + showCancel: true, + confirmText: '涓嬭浇', + cancelText: '鍙栨秷', + success: (res) => { + if (res.confirm) { + // 鐢ㄦ埛閫夋嫨涓嬭浇鏂囦欢 + const item = { fattach: fileName, itemNo: this.selectedAttachment.itemNo }; + this.downloadAttachment(item); + } + } + }); + }, + + downloadAttachment(item) { + // 鍘婚櫎鎵�鏈夌┖鏍笺�佸叏瑙掔┖鏍笺�佸洖杞︺�佹崲琛� + const fileName = item.fattach.replace(/[\s\u3000\r\n]+/g, '').trim(); + // 浣跨敤閰嶇疆鐨勬湇鍔″櫒鍦板潃鍜孎TP鏈嶅姟鍣ㄥ湴鍧� + const url = this.$store.state.serverInfo.serverAPI + "/LLJ/DownloadFtpFile?itemNo=" + encodeURIComponent(item.itemNo) + "&fileName=" + encodeURIComponent(fileName) + "&ftpServer=" + encodeURIComponent(this.$store.state.serverInfo.ftpServer); + + // 妫�鏌ヨ繍琛岀幆澧� + // #ifdef H5 + // H5鐜锛氫娇鐢ㄦ祻瑙堝櫒涓嬭浇 + this.downloadFileInBrowser(url, fileName); + // #endif + + // #ifdef APP-PLUS + // APP鐜锛氫娇鐢╱ni.downloadFile + this.downloadFileInApp(url, fileName); + // #endif + + // #ifdef MP + // 灏忕▼搴忕幆澧冿細浣跨敤uni.downloadFile + this.downloadFileInApp(url, fileName); + // #endif + }, + + // 鍦ㄦ祻瑙堝櫒涓笅杞芥枃浠� + downloadFileInBrowser(url, fileName) { + uni.showLoading({ title: '姝e湪鍑嗗涓嬭浇...' }); + + // 鏂规硶1锛氬垱寤洪殣钘忕殑a鏍囩涓嬭浇 + try { + const link = document.createElement('a'); + link.href = url; + link.download = fileName; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + uni.hideLoading(); + uni.showToast({ + title: '涓嬭浇宸插紑濮�', + icon: 'success', + duration: 2000 + }); + } catch (error) { + console.log('a鏍囩涓嬭浇澶辫触锛屽皾璇晈indow.open鏂瑰紡:', error); + // 鏂规硶2锛氫娇鐢╳indow.open + try { + window.open(url, '_blank'); + uni.hideLoading(); + uni.showToast({ + title: '涓嬭浇宸插紑濮�', + icon: 'success', + duration: 2000 + }); + } catch (error2) { + console.log('window.open涓嬭浇澶辫触锛屽皾璇昮etch鏂瑰紡:', error2); + // 鏂规硶3锛氫娇鐢╢etch涓嬭浇 + this.downloadFileWithFetch(url, fileName); + } + } + }, + + // 浣跨敤fetch涓嬭浇鏂囦欢 + downloadFileWithFetch(url, fileName) { + fetch(url) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.blob(); + }) + .then(blob => { + // 鍒涘缓blob URL + const blobUrl = window.URL.createObjectURL(blob); + + // 鍒涘缓涓嬭浇閾炬帴 + const link = document.createElement('a'); + link.href = blobUrl; + link.download = fileName; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + + // 閲婃斁blob URL + window.URL.revokeObjectURL(blobUrl); + + uni.hideLoading(); + uni.showToast({ + title: '涓嬭浇鎴愬姛', + icon: 'success', + duration: 2000 + }); + }) + .catch(error => { + console.error('Fetch涓嬭浇澶辫触:', error); + uni.hideLoading(); + if (error.message.includes('404')) { + uni.showModal({ + title: '鏂囦欢涓嶅瓨鍦�', + content: `璇ラ檮浠跺湪FTP鏈嶅姟鍣ㄤ笂涓嶅瓨鍦╜, + showCancel: false + }); + } else { + uni.showModal({ + title: '涓嬭浇澶辫触', + content: `涓嬭浇澶辫触: ${error.message}`, + showCancel: false + }); + } + }); + }, + + // 鍦ˋPP涓笅杞芥枃浠� + downloadFileInApp(url, fileName) { + // #ifdef APP-PLUS + uni.showLoading({ title: '浠嶧TP鏈嶅姟鍣ㄤ笅杞戒腑...' }); + + // Android 鑾峰彇瀛樺偍璺緞 + const saveDir = plus.os.name === 'Android' ? plus.io.convertLocalFileSystemURL('_downloads/') : plus.io.convertLocalFileSystemURL('_documents/'); + const filePath = `${saveDir}${fileName}`; + + const downloadTask = uni.downloadFile({ + url: url, + filePath: filePath, // 鎸囧畾淇濆瓨璺緞 + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + const fileInfo = { + name: fileName, + path: res.filePath || filePath, + tempPath: res.tempFilePath + }; + + uni.showModal({ + title: '涓嬭浇鎴愬姛', + content: `鏂囦欢宸蹭繚瀛樺埌锛�${fileInfo.path}`, + showCancel: true, + confirmText: '鎵撳紑鏂囦欢', + cancelText: '纭畾', + success: (modalRes) => { + if (modalRes.confirm) { + // 鐢ㄦ埛閫夋嫨鎵撳紑鏂囦欢 + this.openFileInApp(fileInfo); + } + } + }); + } else if (res.statusCode === 404) { + uni.showModal({ + title: '鏂囦欢涓嶅瓨鍦�', + content: `璇ラ檮浠跺湪FTP鏈嶅姟鍣ㄤ笂涓嶅瓨鍦╜, + showCancel: false + }); + } else { + uni.showModal({ + title: '涓嬭浇澶辫触', + content: `鐘舵�佺爜锛�${res.statusCode}`, + showCancel: false + }); + } + }, + fail: (error) => { + uni.hideLoading(); + console.error('涓嬭浇澶辫触:', error); + uni.showModal({ + title: '涓嬭浇澶辫触', + content: `缃戠粶閿欒锛�${error.errMsg}`, + showCancel: false + }); + } + }); + + // 鐩戝惉涓嬭浇杩涘害 + downloadTask.onProgressUpdate((res) => { + const progress = Math.round(res.progress); + uni.showLoading({ + title: `涓嬭浇涓� ${progress}%`, + mask: true + }); + }); + // #endif + + // #ifdef MP + // 灏忕▼搴忕幆澧冪殑绠�鍖栧疄鐜� + uni.showLoading({ title: '涓嬭浇涓�...' }); + uni.downloadFile({ + url: url, + success: (res) => { + uni.hideLoading(); + if (res.statusCode === 200) { + uni.showToast({ title: '涓嬭浇瀹屾垚', icon: 'success' }); + } + }, + fail: (error) => { + uni.hideLoading(); + uni.showModal({ title: '涓嬭浇澶辫触', content: error.errMsg, showCancel: false }); + } + }); + // #endif + }, + + // APP涓墦寮�鏂囦欢 + openFileInApp(fileInfo) { + // #ifdef APP-PLUS + if (typeof plus !== 'undefined') { + const filePath = fileInfo.path || fileInfo.tempPath; + + // 灏濊瘯鎵撳紑鏂囦欢 + plus.runtime.openFile(filePath, {}, (error) => { + console.error('鎵撳紑鏂囦欢澶辫触:', error); + uni.showModal({ + title: '鏃犳硶鎵撳紑', + content: '绯荤粺涓病鏈夋壘鍒拌兘鎵撳紑姝ゆ枃浠剁殑搴旂敤绋嬪簭', + showCancel: false + }); + }); + } + // #endif }, } @@ -1368,9 +1867,11 @@ font-family: 'Microsoft YaHei', 'Segoe UI', sans-serif; max-width: 1000px; margin: 0 auto; - padding: 20px; + padding: 20px 20px 160px 20px; /* 搴曢儴澧炲姞padding涓哄浐瀹氭寜閽暀绌洪棿 */ background-color: #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); + min-height: 100vh; + position: relative; } /* 澶撮儴鏍峰紡 */ @@ -1491,7 +1992,60 @@ background-color: #f1f5f9; } - /* 鎸夐挳鏍峰紡 */ + /* 鍥哄畾搴曢儴鎸夐挳鏍峰紡 */ + .fixed-action-buttons { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background-color: #fff; + box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1); + padding: 10px 15px 20px 15px; + z-index: 100; + display: flex; + flex-direction: column; + gap: 8px; + max-height: 150px; + overflow-y: auto; + } + + .action-btn { + background-color: #ecf0f1; + color: #34495e; + padding: 12px 15px; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: 500; + transition: all 0.3s ease; + text-align: center; + min-height: 44px; + display: flex; + align-items: center; + justify-content: center; + } + + .action-btn:hover { + background-color: #d5dbdb; + transform: translateY(-1px); + } + + .action-btn.primary { + background-color: #3498db; + color: #fff; + } + + .action-btn.primary:hover { + background-color: #2980b9; + } + + /* 鍐呭鍖呰鍣紝涓哄簳閮ㄦ寜閽暀鍑虹┖闂� */ + .content-wrapper { + height: 20px; /* 棰濆鐨勭┖鐧藉尯鍩� */ + } + + /* 鍘熸湁鎸夐挳鏍峰紡淇濇寔鍏煎 */ .action-buttons { display: flex; gap: 10px; @@ -1600,7 +2154,7 @@ display: flex; justify-content: center; align-items: center; - z-index: 10; + z-index: 1000; /* 鎻愰珮灞傜骇锛岀‘淇濆湪鍥哄畾鎸夐挳涓婃柟 */ } /* 寮圭獥鏁翠綋缇庡寲 */ @@ -1612,6 +2166,9 @@ border: none; position: relative; min-width: 260px; + z-index: 1001; /* 纭繚寮圭獥鍐呭鍦ㄦ渶涓婂眰 */ + max-height: 80vh; /* 闄愬埗鏈�澶ч珮搴︼紝閬垮厤琚簳閮ㄦ寜閽伄鎸� */ + overflow-y: auto; /* 鍐呭杩囧鏃跺彲婊氬姩 */ } .attachment-popup-title { font-size: 22px; @@ -1690,6 +2247,164 @@ background: linear-gradient(90deg,#bdbdbd 0%,#e0e0e0 100%); color: #1976d2; } + + /* 闄勪欢璇︽儏椤甸潰鐨勬搷浣滄寜閽� */ + .attachment-actions-detail { + margin: 20px 0; + display: flex; + gap: 12px; + justify-content: center; + flex-wrap: wrap; + } + .attachment-action-btn { + padding: 10px 20px; + border: none; + border-radius: 8px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + min-width: 120px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + } + .attachment-action-btn.preview-btn { + background: linear-gradient(135deg, #4CAF50, #45a049); + color: white; + } + .attachment-action-btn.preview-btn:hover { + background: linear-gradient(135deg, #45a049, #3d8b40); + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0,0,0,0.15); + } + .attachment-action-btn.download-btn { + background: linear-gradient(135deg, #2196F3, #1976D2); + color: white; + } + .attachment-action-btn.download-btn:hover { + background: linear-gradient(135deg, #1976D2, #1565C0); + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0,0,0,0.15); + } + + /* 鏂囦欢棰勮寮圭獥鏍峰紡 */ + .file-preview-popup { + width: 80vw; + max-width: 600px; + max-height: 70vh; + display: flex; + flex-direction: column; + } + + /* APP鐜閫傞厤 */ + /* #ifdef APP-PLUS */ + .file-preview-popup { + width: 85vw; + max-height: 75vh; + } + .file-preview-content { + max-height: 350px; + } + /* #endif */ + .file-preview-title { + font-size: 18px; + font-weight: 700; + color: #222; + margin-bottom: 8px; + text-align: center; + word-break: break-all; + } + .file-preview-divider { + height: 1px; + background: linear-gradient(90deg,#e0e7ef 0%,#f5f7fa 100%); + margin-bottom: 16px; + } + .file-preview-content { + flex: 1; + max-height: 400px; + overflow-y: auto; + background: #f8fafc; + border-radius: 8px; + padding: 16px; + margin-bottom: 16px; + border: 1px solid #e2e8f0; + } + .file-preview-content pre { + font-family: 'Consolas', 'Monaco', 'Courier New', monospace; + font-size: 12px; + line-height: 1.5; + color: #2d3748; + white-space: pre-wrap; + word-wrap: break-word; + margin: 0; + } + + /* 鍥剧墖棰勮鏍峰紡 */ + .image-preview-container { + display: flex; + justify-content: center; + align-items: center; + min-height: 200px; + } + + /* 涓嶆敮鎸佹枃浠剁被鍨嬬殑鎻愮ず鏍峰紡 */ + .unsupported-preview { + text-align: center; + padding: 40px 20px; + color: #666; + } + .unsupported-icon { + font-size: 48px; + margin-bottom: 16px; + } + .unsupported-text { + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 8px; + } + .unsupported-hint { + font-size: 14px; + color: #999; + line-height: 1.4; + } + + .file-preview-actions { + display: flex; + gap: 12px; + justify-content: center; + } + .file-preview-btn { + padding: 8px 20px; + border: none; + border-radius: 6px; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + min-width: 120px; + } + .file-preview-btn.download-btn { + background: linear-gradient(135deg, #2196F3, #1976D2); + color: white; + } + .file-preview-btn.download-btn:hover { + background: linear-gradient(135deg, #1976D2, #1565C0); + transform: translateY(-1px); + } + .file-preview-btn.close-btn { + background: linear-gradient(135deg, #e0e0e0, #bdbdbd); + color: #444; + } + .file-preview-btn.close-btn:hover { + background: linear-gradient(135deg, #bdbdbd, #9e9e9e); + transform: translateY(-1px); + } /* 鍒楄〃寮圭獥缇庡寲锛堜繚鐣欏師鏈夛級 */ .attachment-list { padding: 0; @@ -1702,24 +2417,36 @@ display: flex; align-items: center; justify-content: space-between; - padding: 8px 0; + padding: 12px 0; border-bottom: 1px solid #f0f0f0; } - .attachment-name { + .attachment-info { flex: 1; + margin-right: 10px; + } + .attachment-name { color: #3498db; cursor: pointer; font-weight: 500; transition: color 0.2s; - margin-right: 10px; + display: block; + margin-bottom: 4px; } .attachment-name:hover { color: #217dbb; text-decoration: underline; } + .attachment-meta { + font-size: 12px; + } + .attachment-type { + color: #7f8c8d; + font-style: italic; + } .attachment-actions { display: flex; gap: 8px; + flex-shrink: 0; } .attachment-list .secondary-btn { padding: 4px 10px; @@ -1734,6 +2461,15 @@ background: #e6f0fa; color: #1976d2; } + .preview-btn { + background: #e8f5e8 !important; + color: #2e7d2e !important; + border-color: #a5d6a5 !important; + } + .preview-btn:hover { + background: #d4eecc !important; + color: #1e5f1e !important; + } .attachment-popup-close { margin-top: 18px; width: 100%; diff --git a/store/index.js b/store/index.js index d92d393..e087f48 100644 --- a/store/index.js +++ b/store/index.js @@ -10,9 +10,10 @@ networkFlag:'鍐呯綉', serverURLInt:'http://192.168.11.251:10055',//鏈嶅姟鍣ㄤ綋妫� 10.0.1.104:10054 serverURL:'http://localhost:10055',//鏈湴璋冭瘯鍦板潃 - serverAPI:'http://localhost:5184/api',//褰撳墠姝e湪浣跨敤鐨勬湇鍔″櫒,榛樿涓哄缃� localhost + // serverAPI:'http://localhost:5184/api',//褰撳墠姝e湪浣跨敤鐨勬湇鍔″櫒,榛樿涓哄缃� localhost //serverAPI:'http://192.168.1.22:10054/api',//鍐呯綉 - //serverAPI:'http://36.26.21.214:10054/api', + serverAPI:'http://36.26.21.214:10054/api', + ftpServer:'ftp://36.26.21.214',//FTP鏈嶅姟鍣ㄥ湴鍧� } }, mutations: { -- Gitblit v1.9.3