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

feat(miniprogram): 图片上传统一支持从聊天记录选择图片

E2E Test Bot пре 5 дана
родитељ
комит
699887fd92

+ 2 - 1
cfc-frontend/pages/action-detail/interaction-log.vue

@@ -128,6 +128,7 @@
 import { getFamilyMemberList, addInteraction, reportAppEnter
 } from '../../utils/api.js'
 import config from '../../config.js'
+import { pickImage } from '../../utils/image-picker.js'
 
 export default {
   data() {
@@ -229,7 +230,7 @@ export default {
       var remaining = 9 - self.photos.length
       if (remaining <= 0) return
 
-      uni.chooseImage({
+      pickImage({
         count: remaining,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],

+ 2 - 1
cfc-frontend/pages/activity/create.vue

@@ -131,6 +131,7 @@ import { adminCreateActivity, adminUpdateActivity, adminPublishActivity, submitA
 import config from '../../config.js'
 import { parseDate } from '../../utils/format.js'
 import { hasActivityManageRole } from '../../utils/activity-role.js'
+import { pickImage } from '../../utils/image-picker.js'
 
 var BASE_URL = config.api('')
 
@@ -318,7 +319,7 @@ export default {
     },
     chooseImage() {
       var self = this
-      uni.chooseImage({
+      pickImage({
         count: 1,
         sizeType: ['compressed'],
         success: function(res) {

+ 2 - 1
cfc-frontend/pages/article-center/article-edit.vue

@@ -98,6 +98,7 @@
 <script>
 import { publishArticle } from '@/utils/api.js'
 import config from '@/config.js'
+import { pickImage } from '@/utils/image-picker.js'
 
 export default {
   data() {
@@ -125,7 +126,7 @@ export default {
   methods: {
     chooseCover() {
       var self = this
-      uni.chooseImage({
+      pickImage({
         count: 1,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],

+ 2 - 1
cfc-frontend/pages/assessment/upload-report.vue

@@ -39,6 +39,7 @@
 
 <script>
 import { uploadAssessmentReport } from '../../utils/api.js'
+import { pickImage } from '../../utils/image-picker.js'
 
 export default {
   data() {
@@ -74,7 +75,7 @@ export default {
       }
     },
     chooseFile() {
-      uni.chooseImage({
+      pickImage({
         count: 1,
         success: (res) => {
           this.file = res.tempFiles[0]

+ 2 - 1
cfc-frontend/pages/growth/diet-checkin.vue

@@ -163,6 +163,7 @@ import config from '../../config'
 import { parseDate } from '../../utils/format.js'
 import { sttTranscribe, recognizeDietFood } from '../../utils/api.js'
 import shareMixin from '../../components/share-mixin.js'
+import { pickImage } from '../../utils/image-picker.js'
 
 export default {
   mixins: [shareMixin],
@@ -296,7 +297,7 @@ export default {
     },
     choosePhoto: function() {
       var self = this
-      uni.chooseImage({
+      pickImage({
         count: 9 - self.form.photos.length,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],

+ 2 - 1
cfc-frontend/pages/growth/exercise-checkin.vue

@@ -156,6 +156,7 @@
 import config from '../../config'
 import { parseDate } from '../../utils/format.js'
 import { sttTranscribe } from '../../utils/api.js'
+import { pickImage } from '../../utils/image-picker.js'
 
 export default {
   data() {
@@ -286,7 +287,7 @@ export default {
     },
     choosePhoto: function() {
       var self = this
-      uni.chooseImage({
+      pickImage({
         count: 9 - self.form.photos.length,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],

+ 2 - 1
cfc-frontend/pages/guide/packages/create.vue

@@ -51,6 +51,7 @@
 
 <script>
 import { createPackage } from '@/utils/api.js'
+import { pickImage } from '@/utils/image-picker.js'
 
 export default {
   data() {
@@ -76,7 +77,7 @@ export default {
       this.form.isPublic = e.detail.value
     },
     chooseImage() {
-      uni.chooseImage({
+      pickImage({
         count: 1,
         success: (res) => {
           this.form.coverImage = res.tempFilePaths[0]

+ 2 - 1
cfc-frontend/pages/guide/register/index.vue

@@ -139,6 +139,7 @@
 
 <script>
 import { registerGuide, validateInviteCode } from '../../../utils/api.js'
+import { pickImage } from '@/utils/image-picker.js'
 
 export default {
   onLoad() {
@@ -201,7 +202,7 @@ export default {
     },
 
     chooseImage(field) {
-      uni.chooseImage({
+      pickImage({
         count: 1,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],

+ 2 - 1
cfc-frontend/pages/health/report-upload.vue

@@ -138,6 +138,7 @@
 
 <script>
 import { uploadReportOnly, getReportCollectStatus, getFamilyMemberList, requestReportTransfer } from '../../utils/api.js'
+import { pickImage } from '../../utils/image-picker.js'
 
 export default {
   data() {
@@ -294,7 +295,7 @@ if (options.type === 'a2' || options.reportKind === 'a2') {
       var self = this
       if (!this.ensureMember()) return
       this.ensureAgreed(function() {
-        uni.chooseImage({
+        pickImage({
           count: 1,
           sourceType: ['camera', 'album'],
           success: function(res) {

+ 2 - 1
cfc-frontend/pages/invite/join-form.vue

@@ -49,6 +49,7 @@
 
 <script>
 import { updateUserInfo, requestJoinByCode } from '@/utils/api.js'
+import { pickImage } from '@/utils/image-picker.js'
 
 export default {
 	data() {
@@ -93,7 +94,7 @@ export default {
 		},
 		chooseAvatar() {
 			var self = this
-			uni.chooseImage({
+			pickImage({
 				count: 1,
 				success: function(res) {
 					self.form.avatar = res.tempFilePaths[0]

+ 2 - 1
cfc-frontend/pages/mind-detail/emotion-checkin.vue

@@ -202,6 +202,7 @@
 <script>
 import config from '../../config'
 import PsychCrisisBanner from '@/pages/mind-detail/components/PsychCrisisBanner.vue'
+import { pickImage } from '@/utils/image-picker.js'
 
 export default {
   components: { PsychCrisisBanner },
@@ -506,7 +507,7 @@ export default {
     takeMedia() {
       var self = this
       if (this.captureMode === 'photo') {
-        uni.chooseImage({
+        pickImage({
           count: 1,
           sourceType: ['camera', 'album'],
           success: function(res) {

+ 3 - 2
cfc-frontend/pages/profile/service-role-apply.vue

@@ -123,6 +123,7 @@
 
 <script>
 import { submitServiceRoleApply, getMyServiceRoleApply, uploadServiceRoleImage } from '../../utils/api'
+import { pickImage } from '../../utils/image-picker.js'
 import AddressPicker from '@/components/address-picker.vue'
 
 export default {
@@ -237,7 +238,7 @@ export default {
       }
     },
     chooseIdCardImage(side) {
-      uni.chooseImage({
+      pickImage({
         count: 1,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],
@@ -264,7 +265,7 @@ export default {
       })
     },
     async chooseCertificate() {
-      uni.chooseImage({
+      pickImage({
         count: 9 - this.form.certificateImages.length,
         sizeType: ['compressed'],
         sourceType: ['album', 'camera'],

+ 4 - 3
cfc-frontend/pages/user-edit/user-edit.vue

@@ -264,6 +264,7 @@
 <script>
 import { updateUserInfo, createFamily, directRegister, getUserInfo, requestJoinByCode, getMyMembership, bindReferralIfNotSelf } from '../../utils/api.js'
 import AddressPicker from '@/components/address-picker.vue'
+import { pickImage } from '@/utils/image-picker.js'
 
 export default {
 	components: { AddressPicker },
@@ -384,7 +385,7 @@ export default {
 			}
 		},
 		chooseAvatar() {
-			uni.chooseImage({
+			pickImage({
 				count: 1,
 				success: (res) => {
 					this.form.avatar = res.tempFilePaths[0]
@@ -392,7 +393,7 @@ export default {
 			})
 		},
 		chooseTeacherPhoto() {
-			uni.chooseImage({
+			pickImage({
 				count: 1,
 				success: (res) => {
 					this.form.teacherPhoto = res.tempFilePaths[0]
@@ -400,7 +401,7 @@ export default {
 			})
 		},
 		chooseCertificate() {
-			uni.chooseImage({
+			pickImage({
 				count: 1,
 				success: (res) => {
 					this.form.certificateImage = res.tempFilePaths[0]

+ 18 - 1
cfc-frontend/pages/wealth-sub/insurance-add.vue

@@ -221,11 +221,13 @@ export default {
     chooseFile() {
       var self = this
       uni.showActionSheet({
-        itemList: ['从聊天选取PDF', '拍照上传'],
+        itemList: ['从聊天选取PDF', '从聊天选取图片', '拍照/相册上传'],
         success: function(res) {
           if (res.tapIndex === 0) {
             self.chooseChatFile()
           } else if (res.tapIndex === 1) {
+            self.chooseChatImage()
+          } else if (res.tapIndex === 2) {
             self.takePhoto()
           }
         },
@@ -248,6 +250,21 @@ export default {
       })
     },
 
+    chooseChatImage() {
+      var self = this
+      uni.chooseMessageFile({
+        count: 1,
+        type: 'image',
+        success: function(res) {
+          var files = res.tempFiles
+          if (files && files.length > 0) {
+            self.uploadAndParse(files[0].path, files[0].name || '聊天图片')
+          }
+        },
+        fail: function() {}
+      })
+    },
+
     takePhoto() {
       var self = this
       uni.chooseImage({

+ 110 - 0
cfc-frontend/utils/image-picker.js

@@ -0,0 +1,110 @@
+/**
+ * 统一图片选择器(微信小程序支持「从聊天记录选择图片」)
+ *
+ * 背景:
+ *   uni.chooseImage 只能从 album(手机相册)或 camera(拍照)选图,
+ *   无法直接选择聊天记录里的图片;微信小程序要从聊天记录选图,
+ *   必须调用 uni.chooseMessageFile({ type: 'image' })。
+ *   为保证小程序端所有图片上传入口都能从聊天记录选图,统一使用本方法。
+ *
+ * 用法与 uni.chooseImage 基本一致(回调风格):
+ *   pickImage({
+ *     count: 1,
+ *     sizeType: ['compressed'],
+ *     sourceType: ['album', 'camera'], // 可选,默认 ['album', 'camera']
+ *     success: function (res) {
+ *       // res.tempFilePaths: 图片本地临时路径数组
+ *       // res.tempFiles:     [{ path, size, name, type }]
+ *     },
+ *     fail: function (err) {}
+ *   })
+ *
+ * 说明:
+ *   微信小程序下会先弹出 ActionSheet:拍照 / 从相册选择 / 从聊天记录选择,
+ *   前两项走 uni.chooseImage,最后一项走 uni.chooseMessageFile。
+ *   非微信平台(H5/App 等)不支持聊天记录选图,保持原 uni.chooseImage 行为。
+ */
+export function pickImage(options) {
+  var opts = options || {}
+  var count = opts.count || 9
+  var sizeType = opts.sizeType || ['original', 'compressed']
+  var sourceType = opts.sourceType || ['album', 'camera']
+  var success = opts.success
+  var fail = opts.fail
+  var complete = opts.complete
+
+  function onSuccess(res) {
+    if (success) success(res)
+    if (complete) complete(res)
+  }
+
+  function onFail(err) {
+    if (fail) fail(err)
+    if (complete) complete(err)
+  }
+
+  // sourceType 只支持单个来源时(如 ['camera'])直接调起对应入口
+  function callChooseImage(types) {
+    uni.chooseImage({
+      count: count,
+      sizeType: sizeType,
+      sourceType: types,
+      success: onSuccess,
+      fail: onFail
+    })
+  }
+
+  // #ifdef MP-WEIXIN
+  // 微信小程序:先选来源,再从聊天记录 / 相册 / 相机取图
+  var actionList = []
+  if (sourceType.indexOf('camera') > -1) actionList.push({ label: '拍照', type: 'camera' })
+  if (sourceType.indexOf('album') > -1) actionList.push({ label: '从相册选择', type: 'album' })
+  actionList.push({ label: '从聊天记录选择', type: 'chat' })
+
+  var itemList = []
+  for (var i = 0; i < actionList.length; i++) itemList.push(actionList[i].label)
+
+  uni.showActionSheet({
+    itemList: itemList,
+    success: function (sheetRes) {
+      var action = actionList[sheetRes.tapIndex]
+      if (!action) return
+      if (action.type !== 'chat') {
+        callChooseImage([action.type])
+        return
+      }
+      if (typeof uni.chooseMessageFile !== 'function') {
+        // 低版本基础库不支持聊天记录选图,降级为相册选图
+        callChooseImage(['album'])
+        return
+      }
+      uni.chooseMessageFile({
+        count: count,
+        type: 'image',
+        success: function (res) {
+          var files = []
+          var tempFiles = res.tempFiles || []
+          for (var j = 0; j < tempFiles.length; j++) {
+            files.push({
+              path: tempFiles[j].path,
+              size: tempFiles[j].size,
+              name: tempFiles[j].name,
+              type: tempFiles[j].type
+            })
+          }
+          var paths = []
+          for (var k = 0; k < files.length; k++) paths.push(files[k].path)
+          onSuccess({ tempFilePaths: paths, tempFiles: files })
+        },
+        fail: onFail
+      })
+    },
+    fail: onFail
+  })
+  // #endif
+
+  // #ifndef MP-WEIXIN
+  // 非微信平台不支持聊天记录选图,保持原行为
+  callChooseImage(sourceType)
+  // #endif
+}