Explorar el Código

feat:仓库模块图片拖拽

zhangxin hace 2 semanas
padre
commit
4563471576

+ 119 - 61
components/add-inquiry-dialog/index.vue

@@ -1,58 +1,62 @@
1 1
 <template>
2
-	<view>
3
-		<u-modal :show="showModal" ref="uModal" :asyncClose="false" showCancelButton @cancel="closeDialog" cancelColor="#909399" :confirmText="'确定'" confirmColor="#2979ff" @confirm="confirm" @close="closeDialog" :closeOnClickOverlay="false">
2
+    <view>
3
+        <u-modal :show="showModal" ref="uModal" :asyncClose="false" showCancelButton @cancel="closeDialog"
4
+            cancelColor="#909399" :confirmText="'确定'" confirmColor="#2979ff" @confirm="confirm" @close="closeDialog"
5
+            :closeOnClickOverlay="false">
4 6
             <view class="title_wrap">
5 7
                 <view class="title">
6 8
                     {{ title }}
7 9
                 </view>
8 10
                 <view class="modal_wrap">
9
-                    <text @click="handleBrandClick" class="item" :class="info.dictLabel ? 'brand' : 'brand placeholder'">{{ info.dictLabel || '品牌' }}</text>
11
+                    <text @click="handleBrandClick" class="item"
12
+                        :class="info.dictLabel ? 'brand' : 'brand placeholder'">{{ info.dictLabel || '品牌' }}</text>
10 13
                     <text class="divider">|</text>
11 14
                     <u--input placeholder="型号" class="item" border="none" v-model="info.model" clearable></u--input>
12 15
                     <text class="divider">|</text>
13
-                    <u--input class="code-input item" placeholder="编码" border="none" v-model="info.code" clearable></u--input>
16
+                    <u--input class="code-input item" placeholder="编码" border="none" v-model="info.code"
17
+                        clearable></u--input>
14 18
                 </view>
15 19
             </view>
16 20
             <view class="img_wrap">
17
-                <imgs-row-scroll v-if="info.imgsUrl.length > 0" :isShowDeleteIcon="true" @deleteImgInfo="getDeleteImgInfo" imgMode="aspectFill" :totalWidth="400" :images="info.imgsUrl" :previewEnabled="true" :imageWidth="150" :imageHeight="150"></imgs-row-scroll>
18
-                <u-upload
19
-                    @afterRead="afterRead"
20
-                    name="3"
21
-                    multiple
22
-                    :maxCount="10"
23
-                ></u-upload>
21
+                <imgs-row-scroll v-if="info.imgsUrl.length > 0" :isShowDeleteIcon="true"
22
+                    @deleteImgInfo="getDeleteImgInfo" imgMode="aspectFill" :totalWidth="400" :images="info.imgsUrl"
23
+                    :previewEnabled="true" :imageWidth="150" :imageHeight="150"></imgs-row-scroll>
24
+                <u-upload @afterRead="afterRead" name="3" multiple :maxCount="10"></u-upload>
24 25
             </view>
25
-            <u--input v-if="editOrAdd === 'edit'" class="price" placeholder="价格" border="bottom" v-model="info.price" clearable></u--input>
26
+            <u--input v-if="editOrAdd === 'edit'" class="price" placeholder="价格" border="bottom" v-model="info.price"
27
+                clearable></u--input>
28
+            <qiun-data-charts v-if="isShowChart" type="column" :chartData="chartData" canvasId="priceChart" :opts="opts" :ontouch="true"
29
+                width="700rpx" height="600rpx" backgroundColor="#fff" />
26 30
         </u-modal>
27 31
         <brandList ref="brandListRef" @selectedBrand="handleSelectedBrand"></brandList>
28
-	</view>
32
+    </view>
29 33
 </template>
30 34
 
31 35
 <script>
32 36
 import imgsRowScroll from '@/components/imgs-row-scroll/index.vue'
33 37
 import brandList from '@/components/brand-list/index.vue'
34 38
 export default {
35
-	name: 'AddInquiryDialog',
39
+    name: 'AddInquiryDialog',
36 40
     components: {
37 41
         imgsRowScroll,
38 42
         brandList
39 43
     },
40
-	props: {
44
+    props: {
41 45
         clueId: {
42 46
             type: String,
43 47
             default: ''
44 48
         },
45
-		show: {
46
-			type: Boolean,
47
-			default: false
48
-		},
49
+        show: {
50
+            type: Boolean,
51
+            default: false
52
+        },
49 53
         editOrAdd: {
50 54
             type: String,
51 55
             default: ''// edit 编辑(有价格), editForm 编辑询价单(无价格), add 新增询价单, receptFormAdd 新增接收询价单   线索页面:第一次点击是新增(不需要回显),status传1,第二次点击是无价格编辑status传1;接单中心:第一次点击是新增(需要回显)status传1,第二次点击是无价格编辑status传1;只有edit是有价格编辑status传2
52 56
         },
53 57
         editInfo: {
54 58
             type: Object,
55
-            default: () => {}
59
+            default: () => { }
56 60
         },
57 61
         type: {
58 62
             type: Number,
@@ -62,50 +66,104 @@ export default {
62 66
             type: Boolean,
63 67
             default: false
64 68
         },
65
-        title:{
69
+        title: {
66 70
             type: String,
67 71
             default: ''
72
+        },
73
+        isShowChart: {
74
+            type: Boolean,
75
+            default: false
68 76
         }
69
-	},
77
+    },
70 78
     emits: ['submitSuccess'],
71 79
     inject: {
72 80
         refreshData: {
73 81
             default: null
74 82
         }
75 83
     },
76
-	data() {
77
-		return {
78
-			showModal: false,
84
+    data() {
85
+        return {
86
+            showModal: false,
79 87
             info: {
80
-                model:'',
81
-                code:'',
82
-                id:'',
83
-                price:'',
84
-                dictLabel:'',
85
-                dictValue:'',
86
-                imgsUrl:[]
88
+                model: '',
89
+                code: '',
90
+                id: '',
91
+                price: '',
92
+                dictLabel: '',
93
+                dictValue: '',
94
+                imgsUrl: []
87 95
             },
88 96
             rules: {
89 97
                 brand: [
90 98
                     { required: true, message: '请输入品牌', trigger: 'blur' }
91 99
                 ]
92 100
             },
93
-            
94
-		}
95
-	},
96
-	watch: {
97
-		show: {
98
-			handler(newVal) {
99
-				this.showModal = newVal;
100
-			},
101
-			immediate: true
102
-		}
103
-	},
104
-	methods: {
101
+            opts: {
102
+                color: [this.getRandomColor()],
103
+                padding: [15, 15, 0, 5],
104
+                touchMoveLimit: 24,
105
+                enableScroll: true,
106
+                legend: {},
107
+                xAxis: {
108
+                    disableGrid: true,
109
+                    scrollShow: true,
110
+                    itemCount: 4
111
+                },
112
+                yAxis: {
113
+                    data: [
114
+                        {
115
+                            min: 0
116
+                        }
117
+                    ]
118
+                },
119
+                extra: {
120
+                    column: {
121
+                        type: "group",
122
+                        width: 30,
123
+                        activeBgColor: "#000000",
124
+                        activeBgOpacity: 0.08,
125
+                        seriesGap: 5,
126
+                        barBorderRadius: [6,6,6,6]
127
+                    }
128
+                }
129
+            },
130
+            chartData:{}
131
+
132
+        }
133
+    },
134
+    watch: {
135
+        show: {
136
+            handler(newVal) {
137
+                this.showModal = newVal;
138
+            },
139
+            immediate: true
140
+        }
141
+    },
142
+    methods: {
143
+        getRandomColor() {
144
+            var letters = '0123456789ABCDEF';
145
+            var color = '#';
146
+            for (var i = 0; i < 6; i++) {
147
+                color += letters[Math.floor(Math.random() * 16)];
148
+            }
149
+            return color;
150
+        },
105 151
         // 编辑回显
106 152
         initData() {
107
-            this.$nextTick(()=>{
153
+            this.$nextTick(() => {
108 154
                 this.info = JSON.parse(JSON.stringify(this.editInfo))
155
+                console.log(this.info)
156
+                if(this.isShowChart){
157
+                    this.chartData = {
158
+                        categories: this.info.priceChart.map((item, index) => item.userName),
159
+                        series: [
160
+                            {
161
+                                name: "价格",
162
+                                data: this.info.priceChart.map(item => item.price)
163
+                            }
164
+                        ]
165
+                    };
166
+                }
109 167
                 this.showModal = true;
110 168
             })
111 169
         },
@@ -122,7 +180,7 @@ export default {
122 180
         },
123 181
         // 上传图片
124 182
         afterRead(info) {
125
-            info.file.forEach(item=>{
183
+            info.file.forEach(item => {
126 184
                 uni.$u.api.uploadFile(item.url).then((res) => {
127 185
                     this.info.imgsUrl.push(res.data.url);
128 186
                     uni.$u.toast("文件上传成功");
@@ -154,14 +212,14 @@ export default {
154 212
                 })
155 213
                 return
156 214
             }
157
-            if(this.info.imgsUrl.length == 0){
215
+            if (this.info.imgsUrl.length == 0) {
158 216
                 uni.showToast({
159 217
                     title: '请上传图片',
160 218
                     icon: 'none'
161 219
                 })
162 220
                 return
163 221
             }
164
-            if(this.editOrAdd === 'edit' && !this.info.price){
222
+            if (this.editOrAdd === 'edit' && !this.info.price) {
165 223
                 uni.showToast({
166 224
                     title: '请输入价格',
167 225
                     icon: 'none'
@@ -176,7 +234,7 @@ export default {
176 234
                 code: this.info.code,
177 235
                 id: (this.editOrAdd === 'edit' || this.editOrAdd === 'editForm') ? this.info.id : '',
178 236
                 price: this.editOrAdd === 'edit' ? this.info.price : '',
179
-                imgsUrl:this.info.imgsUrl,
237
+                imgsUrl: this.info.imgsUrl,
180 238
                 status: this.editOrAdd === 'edit' ? '2' : '1',
181 239
                 type: this.type
182 240
             }
@@ -184,7 +242,7 @@ export default {
184 242
                 uni.$u.toast('保存成功')
185 243
                 this.closeDialog()
186 244
                 this.$emit('submitSuccess')
187
-                if(this.isClue && this.refreshData) this.refreshData.resetData(); //线索公海页面需要刷新列表
245
+                if (this.isClue && this.refreshData) this.refreshData.resetData(); //线索公海页面需要刷新列表
188 246
             }).catch((err) => {
189 247
                 uni.$u.toast(err)
190 248
             })
@@ -192,30 +250,30 @@ export default {
192 250
         showDialog() {
193 251
             if (this.editOrAdd === 'edit' || this.editOrAdd === 'editForm' || this.editOrAdd === 'receptFormAdd') {
194 252
                 this.initData();
195
-            }else if(this.editOrAdd === 'add'){
253
+            } else if (this.editOrAdd === 'add') {
196 254
                 this.clearForm()
197 255
                 this.showModal = true;
198 256
             }
199 257
         },
200 258
         clearForm() {
201 259
             this.info = {
202
-                dictLabel:'',
203
-                dictValue:'',
204
-                model:'',
205
-                code:'',
206
-                id:'',
207
-                price:'',
208
-                imgsUrl:[]
260
+                dictLabel: '',
261
+                dictValue: '',
262
+                model: '',
263
+                code: '',
264
+                id: '',
265
+                price: '',
266
+                imgsUrl: []
209 267
             }
210 268
         },
211 269
         closeDialog() {
212 270
             this.showModal = false;
213 271
         },
214
-        
215
-	}
272
+
273
+    }
216 274
 };
217 275
 </script>
218 276
 
219 277
 <style lang="scss" scoped>
220
-    @import './index.scss'
278
+@import './index.scss'
221 279
 </style>

+ 43 - 0
components/drag-upload/PicComp.vue

@@ -0,0 +1,43 @@
1
+<template>
2
+  <view class="pic-comp-container">
3
+    <image 
4
+      class="pic-comp-image" 
5
+      :src="src" 
6
+      mode="aspectFill" 
7
+      @click="handleClick"
8
+    />
9
+  </view>
10
+</template>
11
+
12
+<script>
13
+export default {
14
+  name: 'PicComp',
15
+  props: {
16
+    src: {
17
+      type: String,
18
+      default: ''
19
+    }
20
+  },
21
+  methods: {
22
+    handleClick() {
23
+      this.$emit('needPreviewPic', this.src)
24
+    }
25
+  }
26
+}
27
+</script>
28
+
29
+<style scoped lang="scss">
30
+.pic-comp-container {
31
+  width: 100%;
32
+  height: 100%;
33
+  box-sizing: border-box;
34
+  overflow: hidden;
35
+  border-radius: 30rpx;
36
+}
37
+
38
+.pic-comp-image {
39
+  width: 100% !important;
40
+  height: 100% !important;
41
+  object-fit: cover;
42
+}
43
+</style>

+ 327 - 0
components/drag-upload/imageUpload.js

@@ -0,0 +1,327 @@
1
+/**
2
+ * 图片上传和下载工具类
3
+ */
4
+export default {
5
+  /**
6
+   * 获取文件列表
7
+   * @param {String} type - 类型
8
+   * @param {String} orderFileType - 订单文件类型 (1:聊天记录, 2:实物图, 3:细节图)
9
+   * @param {String} receiptId - 收单ID
10
+   * @param {String} itemBrand - 物品品牌
11
+   * @param {String} clueId - 线索ID
12
+   */
13
+  async getFileList(type, orderFileType, receiptId, itemBrand, clueId) {
14
+    try {
15
+      const params = {
16
+        clueId,
17
+        sourceId: receiptId,
18
+        type,
19
+        orderFileType,
20
+        isDuplicate: '1',
21
+        pageNum: 1,
22
+        pageSize: 1000
23
+      }
24
+      const response = await uni.$u.api.selectClueFileByDto(params)
25
+      const rows = response.rows || []
26
+      
27
+      // 如果品牌包含逗号,说明是多个品牌,需要过滤
28
+      // if (itemBrand && itemBrand.indexOf(',') !== -1) {
29
+        return rows.filter(item => item.sourceId === receiptId)
30
+      // }
31
+      // return rows
32
+    } catch (error) {
33
+      console.error('获取文件列表失败:', error)
34
+      uni.$u.toast('获取文件列表失败')
35
+      return []
36
+    }
37
+  },
38
+
39
+  /**
40
+   * 选择图片
41
+   * @param {Number} count - 最多选择数量
42
+   * @returns {Promise<Array>} 图片路径数组
43
+   */
44
+  chooseImage(count = 9) {
45
+    return new Promise((resolve, reject) => {
46
+      uni.chooseImage({
47
+        count,
48
+        sizeType: ['compressed'],
49
+        sourceType: ['album', 'camera'],
50
+        success: (res) => {
51
+          resolve(res.tempFilePaths)
52
+        },
53
+        fail: (err) => {
54
+          console.error('选择图片失败:', err)
55
+          reject(err)
56
+        }
57
+      })
58
+    })
59
+  },
60
+
61
+  /**
62
+   * 上传文件
63
+   * @param {String} filePath - 文件路径
64
+   * @returns {Promise<Object>} 上传结果
65
+   */
66
+  async uploadFile(filePath) {
67
+    try {
68
+      uni.showLoading({
69
+        title: '上传中...',
70
+        mask: true
71
+      })
72
+      const { data } = await uni.$u.api.uploadFile(filePath)
73
+      return {
74
+        fileSize: data.fileSize,
75
+        fileSuffix: data.fileSuffix,
76
+        fileName: data.name,
77
+        fileUrl: data.url
78
+      }
79
+    } catch (error) {
80
+      console.error('文件上传失败:', error)
81
+      uni.$u.toast('上传失败,请重试')
82
+      throw error
83
+    } finally {
84
+      uni.hideLoading()
85
+    }
86
+  },
87
+
88
+  /**
89
+   * 批量上传文件
90
+   * @param {Array<String>} filePaths - 文件路径数组
91
+   * @returns {Promise<Array>} 上传结果数组
92
+   */
93
+  async uploadFiles(filePaths) {
94
+    try {
95
+      const uploadPromises = filePaths.map(filePath => this.uploadFile(filePath))
96
+      return await Promise.all(uploadPromises)
97
+    } catch (error) {
98
+      console.error('批量上传失败:', error)
99
+      throw error
100
+    }
101
+  },
102
+
103
+  /**
104
+   * 绑定订单文件
105
+   * @param {String} clueId - 线索ID
106
+   * @param {String} receiptId - 收单ID
107
+   * @param {String} orderFileType - 订单文件类型
108
+   * @param {Array} fileList - 文件列表
109
+   */
110
+  async bindOrderFile(clueId, receiptId, orderFileType, fileList) {
111
+    try {
112
+      const list = fileList.map(file => ({
113
+        fileSize: file.fileSize,
114
+        fileSuffix: file.fileSuffix,
115
+        fileName: file.fileName,
116
+        fileUrl: file.fileUrl,
117
+        orderFileType
118
+      }))
119
+      
120
+      await uni.$u.api.saveClueFile({
121
+        clueId,
122
+        list,
123
+        sourceId: receiptId,
124
+        type: '2',
125
+        orderFileType
126
+      })
127
+      uni.$u.toast('上传成功')
128
+    } catch (error) {
129
+      console.error('绑定订单文件失败:', error)
130
+      uni.$u.toast('上传失败')
131
+      throw error
132
+    }
133
+  },
134
+
135
+  /**
136
+   * 删除文件
137
+   * @param {String|Array} fileIds - 文件ID或ID数组
138
+   */
139
+  async deleteFile(fileIds) {
140
+    try {
141
+      const ids = Array.isArray(fileIds) ? fileIds : [fileIds]
142
+      await uni.$u.api.deleteClueFile(ids)
143
+      uni.showToast({
144
+        title: '删除成功',
145
+        icon: 'success',
146
+        duration: 2000
147
+      })
148
+    } catch (error) {
149
+      console.error('删除文件失败:', error)
150
+      uni.showToast({
151
+        title: '删除失败',
152
+        icon: 'error',
153
+        duration: 2000
154
+      })
155
+      throw error
156
+    }
157
+  },
158
+
159
+  /**
160
+   * 保存图片到本地相册
161
+   * @param {String} url - 图片URL
162
+   * @returns {Promise}
163
+   */
164
+  saveImageToLocal(url) {
165
+    return new Promise((resolve, reject) => {
166
+      this._doSaveImage(url, resolve, reject)
167
+    })
168
+  },
169
+
170
+  /**
171
+   * 执行保存图片操作
172
+   * @private
173
+   */
174
+  _doSaveImage(url, resolve, reject) {
175
+    uni.downloadFile({
176
+      url,
177
+      success: (res) => {
178
+        if (res.statusCode === 200 && res.tempFilePath) {
179
+          uni.saveImageToPhotosAlbum({
180
+            filePath: res.tempFilePath,
181
+            success: () => {
182
+              resolve()
183
+            },
184
+            fail: (err) => {
185
+              console.error('保存到相册失败:', err)
186
+              // 错误代码 12 通常表示权限问题
187
+              const isPermissionError = err.code === 12 || 
188
+                                       err.errCode === 12 || 
189
+                                       err.errMsg.includes('auth denied') || 
190
+                                       err.errMsg.includes('permission') ||
191
+                                       err.errMsg.includes('UNKOWN ERROR')
192
+              
193
+              if (isPermissionError) {
194
+                uni.showModal({
195
+                  title: '权限不足',
196
+                  content: '需要访问相册权限来保存图片,是否前往设置开启权限?',
197
+                  confirmText: '去设置',
198
+                  cancelText: '取消',
199
+                  success: (modalRes) => {
200
+                    if (modalRes.confirm) {
201
+                      uni.openSetting({
202
+                        success: (settingRes) => {
203
+                          // 检查是否开启了相册权限
204
+                          const hasPermission = settingRes.authSetting && 
205
+                                              settingRes.authSetting['scope.writePhotosAlbum']
206
+                          if (hasPermission) {
207
+                            uni.showToast({
208
+                              title: '权限已开启,请重试保存',
209
+                              icon: 'none',
210
+                              duration: 2000
211
+                            })
212
+                          } else {
213
+                            uni.showToast({
214
+                              title: '请在设置中开启相册权限',
215
+                              icon: 'none',
216
+                              duration: 2000
217
+                            })
218
+                          }
219
+                        },
220
+                        fail: () => {
221
+                          uni.showToast({
222
+                            title: '无法打开设置',
223
+                            icon: 'none'
224
+                          })
225
+                        }
226
+                      })
227
+                    }
228
+                  }
229
+                })
230
+              } else {
231
+                uni.showToast({
232
+                  title: '保存失败,请稍后重试',
233
+                  icon: 'none'
234
+                })
235
+              }
236
+              reject(err)
237
+            }
238
+          })
239
+        } else {
240
+          const errorMsg = `下载失败,状态码: ${res.statusCode}`
241
+          console.error(errorMsg)
242
+          uni.showToast({
243
+            title: '下载图片失败',
244
+            icon: 'none'
245
+          })
246
+          reject(new Error(errorMsg))
247
+        }
248
+      },
249
+      fail: (err) => {
250
+        console.error('下载图片失败:', err)
251
+        uni.showToast({
252
+          title: '下载图片失败,请检查网络',
253
+          icon: 'none'
254
+        })
255
+        reject(err)
256
+      }
257
+    })
258
+  },
259
+
260
+  /**
261
+   * 批量保存图片到本地
262
+   * @param {Array<String>} urls - 图片URL数组
263
+   */
264
+  async saveImagesToLocal(urls) {
265
+    try {
266
+      uni.showLoading({
267
+        title: '正在保存图片...',
268
+        mask: true
269
+      })
270
+
271
+      const savedImages = []
272
+      const failedImages = []
273
+
274
+      for (let i = 0; i < urls.length; i++) {
275
+        const url = urls[i]
276
+        try {
277
+          await this.saveImageToLocal(url)
278
+          savedImages.push(url)
279
+        } catch (error) {
280
+          console.error(`保存图片失败: ${url}`, error)
281
+          failedImages.push(url)
282
+        }
283
+
284
+        uni.showLoading({
285
+          title: `正在保存图片... (${i + 1}/${urls.length})`,
286
+          mask: true
287
+        })
288
+      }
289
+
290
+      uni.hideLoading()
291
+
292
+      let message = `成功保存 ${savedImages.length} 张图片`
293
+      if (failedImages.length > 0) {
294
+        message += `,${failedImages.length} 张保存失败`
295
+      }
296
+
297
+      uni.showToast({
298
+        title: message,
299
+        icon: 'none',
300
+        duration: 3000
301
+      })
302
+    } catch (error) {
303
+      uni.hideLoading()
304
+      console.error('保存图片过程中发生错误:', error)
305
+      uni.showToast({
306
+        title: '保存图片失败',
307
+        icon: 'error'
308
+      })
309
+    }
310
+  },
311
+
312
+  /**
313
+   * 复制图片链接
314
+   * @param {Array<String>} urls - 图片URL数组
315
+   */
316
+  copyImageUrls(urls) {
317
+    uni.setClipboardData({
318
+      data: JSON.stringify(urls),
319
+      success: () => {
320
+        uni.showToast({
321
+          title: '图片链接已复制',
322
+          icon: 'none'
323
+        })
324
+      }
325
+    })
326
+  }
327
+}

+ 256 - 0
components/drag-upload/index.vue

@@ -0,0 +1,256 @@
1
+<template>
2
+    <view class="detail-image-content">
3
+        <view class="detail-image-list">
4
+            <view v-for="(item, index) in displayImages" :key="`detail-${index}`" class="detail-image-item"
5
+                :class="{
6
+                    'dragging': draggingIndex === index,
7
+                    'can-drop': canDropIndex === index && draggingIndex !== index
8
+                }" :style="draggingIndex === index ? draggingStyle : ''" @touchstart.stop="onTouchStart($event, index)"
9
+                @touchmove.stop="onTouchMove($event, index)" @touchend.stop="onTouchEnd">
10
+                <PicComp :src="item" @needPreviewPic="previewImageDetail" />
11
+                <!-- <view class="image-type-tag">{{ getImageType(index) }}</view> -->
12
+                <view class="detail-delete-btn" @click.stop="handleHideImage(item, index)" v-if="isDelete">
13
+                    ×
14
+                </view>
15
+            </view>
16
+            <view class="detail-upload-btn" @click="handleUploadImage">
17
+                <u-icon name="plus" size="40rpx" color="#999" />
18
+            </view>
19
+        </view>
20
+    </view>
21
+</template>
22
+
23
+<script>
24
+import PicComp from './PicComp.vue'
25
+import imageUpload from './imageUpload.js'
26
+export default {
27
+    name: 'ComponentName',
28
+    components: {
29
+        PicComp
30
+    },
31
+    data() {
32
+        return {
33
+            draggingIndex: -1,
34
+            canDropIndex: -1,
35
+            startX: 0,
36
+            startY: 0,
37
+            currentX: 0,
38
+            currentY: 0,
39
+            currentImgs: []
40
+        }
41
+    },
42
+    watch: {
43
+        images: {
44
+            immediate: true,
45
+            handler(newVal) {
46
+                this.currentImgs = [...newVal]
47
+            }
48
+        }
49
+    },
50
+    computed: {
51
+        displayImages() {
52
+            return this.currentImgs
53
+        },
54
+        // 拖拽时的样式
55
+        draggingStyle() {
56
+            if (this.draggingIndex === -1) return ''
57
+            return {
58
+                transform: `translate(${this.currentX - this.startX}px, ${this.currentY - this.startY}px)`,
59
+                zIndex: 1000
60
+            }
61
+        },
62
+    },
63
+    props: {
64
+        images: {
65
+            type: Array,
66
+            default: () => []
67
+        },
68
+        isDelete: {
69
+            type: Boolean,
70
+            default: false
71
+        },
72
+        isPreview: {
73
+            type: Boolean,
74
+            default: false
75
+        }
76
+    },
77
+    emits: ['imagesChanged', 'uploadComplete'],
78
+    methods: {
79
+        // 触摸开始
80
+        onTouchStart(event, index) {
81
+            if (this.draggingIndex !== -1) return
82
+            this.draggingIndex = index
83
+            const touch = event.touches[0]
84
+            this.startX = touch.clientX
85
+            this.startY = touch.clientY
86
+            this.currentX = touch.clientX
87
+            this.currentY = touch.clientY
88
+        },
89
+
90
+        // 触摸移动
91
+        onTouchMove(event, index) {
92
+            if (this.draggingIndex === -1 || this.draggingIndex !== index) return
93
+            const touch = event.touches[0]
94
+            this.currentX = touch.clientX
95
+            this.currentY = touch.clientY
96
+            this.findTargetIndex(touch.clientX, touch.clientY)
97
+        },
98
+
99
+        // 触摸结束
100
+        async onTouchEnd() {
101
+            if (this.draggingIndex === -1) return
102
+
103
+            if (this.canDropIndex !== -1 && this.canDropIndex !== this.draggingIndex) {
104
+                // 交换位置
105
+                const images = [...this.currentImgs]
106
+                const temp = images[this.draggingIndex]
107
+                images[this.draggingIndex] = images[this.canDropIndex]
108
+                images[this.canDropIndex] = temp
109
+                this.currentImgs = images
110
+            }
111
+
112
+            this.resetDragState()
113
+
114
+            //每次拖拽结束后把新的顺序传给父组件
115
+            this.$emit('imagesChanged', [...this.currentImgs])
116
+        },
117
+        // 查找目标索引
118
+        findTargetIndex(x, y) {
119
+            const query = uni.createSelectorQuery().in(this)
120
+            query.selectAll('.detail-image-item').boundingClientRect((rects) => {
121
+                if (!rects || rects.length === 0) return
122
+                let targetIndex = -1
123
+                for (let i = 0; i < rects.length; i++) {
124
+                    if (i === this.draggingIndex) continue
125
+                    const rect = rects[i]
126
+                    if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
127
+                        targetIndex = i
128
+                        break
129
+                    }
130
+                }
131
+                this.canDropIndex = targetIndex
132
+            }).exec()
133
+        },
134
+
135
+        // 重置拖拽状态
136
+        resetDragState() {
137
+            this.draggingIndex = -1
138
+            this.canDropIndex = -1
139
+            this.startX = 0
140
+            this.startY = 0
141
+            this.currentX = 0
142
+            this.currentY = 0
143
+        },
144
+        // 预览图片
145
+        previewImageDetail(src) {
146
+            if(!this.isPreview){
147
+                return false
148
+            }
149
+            const urlList = this.currentImgs.map(item => item)
150
+            uni.previewImage({
151
+                urls: urlList,
152
+                current: src
153
+            })
154
+        },
155
+        // 隐藏图片
156
+        handleHideImage(item, index) {
157
+            const itemIndex = this.currentImgs.findIndex(img => item === img)
158
+            if (itemIndex !== -1) {
159
+                this.currentImgs.splice(itemIndex, 1)
160
+                // 将更新后的图片数组传给父组件
161
+                this.$emit('imagesChanged', [...this.currentImgs])
162
+                uni.$u.toast('图片已隐藏')
163
+            }
164
+        },
165
+        // 上传图片
166
+        async handleUploadImage() {
167
+            try {
168
+                const filePaths = await imageUpload.chooseImage(9)
169
+                const uploadResults = await imageUpload.uploadFiles(filePaths)
170
+                uploadResults.forEach(item => {
171
+                    this.currentImgs.push(item.fileUrl)
172
+                })
173
+                this.$emit('uploadComplete', this.currentImgs)
174
+            } catch (error) {
175
+                console.error('上传失败:', error)
176
+            }
177
+        },
178
+    }
179
+}
180
+</script>
181
+
182
+<style lang="scss" scoped>
183
+.detail-image-list {
184
+    display: flex;
185
+    flex-wrap: wrap;
186
+    gap: 20rpx;
187
+    position: relative;
188
+
189
+    .detail-image-item {
190
+        position: relative;
191
+        width: 200rpx;
192
+        height: 200rpx;
193
+        touch-action: none;
194
+        transition: transform 0.2s ease, opacity 0.2s ease;
195
+        z-index: 1;
196
+        box-sizing: border-box;
197
+
198
+        &.dragging {
199
+            opacity: 0.6;
200
+            transform: scale(1.05);
201
+            z-index: 999;
202
+            box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.2);
203
+        }
204
+
205
+        &.can-drop {
206
+            outline: 2rpx dashed #108cff;
207
+            outline-offset: -2rpx;
208
+            background-color: rgba(16, 140, 255, 0.1);
209
+            border-radius: 8rpx;
210
+        }
211
+
212
+        // .image-type-tag {
213
+        //     position: absolute;
214
+        //     top: 10rpx;
215
+        //     left: 10rpx;
216
+        //     background-color: rgba(0, 0, 0, 0.6);
217
+        //     color: white;
218
+        //     padding: 5rpx 10rpx;
219
+        //     border-radius: 12rpx;
220
+        //     font-size: 22rpx;
221
+        //     z-index: 1;
222
+        // }
223
+
224
+        .detail-delete-btn {
225
+            position: absolute;
226
+            top: -10rpx;
227
+            right: -10rpx;
228
+            width: 40rpx;
229
+            height: 40rpx;
230
+            background-color: #ff4d4f;
231
+            color: #fff;
232
+            border-radius: 50%;
233
+            display: flex;
234
+            align-items: center;
235
+            justify-content: center;
236
+            font-weight: bold;
237
+            z-index: 10;
238
+            cursor: pointer;
239
+        }
240
+
241
+
242
+    }
243
+
244
+    .detail-upload-btn {
245
+        width: 200rpx;
246
+        height: 200rpx;
247
+        border: 8rpx dashed #ddd;
248
+        border-radius: 30rpx;
249
+        display: flex;
250
+        align-items: center;
251
+        justify-content: center;
252
+        background-color: #f9f9f9;
253
+        cursor: pointer;
254
+    }
255
+}
256
+</style>

+ 11 - 1
components/imgs-row-scroll/index.scss

@@ -16,12 +16,22 @@
16 16
 		background-color: #f5f5f5;
17 17
 		position: relative;
18 18
 		border: 4rpx solid transparent;
19
-		transition: border-color 0.3s;
19
+		transition: border-color 0.3s, transform 0.3s, box-shadow 0.3s;
20 20
 		
21 21
 		&.is-active {
22 22
 			border-color: #3c9cff; // uView 的 primary 颜色
23 23
 			box-shadow: 0 0 12rpx rgba(60, 156, 255, 0.5);
24 24
 		}
25
+		
26
+		&.dragging {
27
+			opacity: 0.5;
28
+			transform: scale(1.05);
29
+			box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.2);
30
+		}
31
+		
32
+		&:hover {
33
+			cursor: move;
34
+		}
25 35
 	}
26 36
 	
27 37
 	.img-content {

+ 1 - 159
components/remote-search-select/index.scss

@@ -86,158 +86,8 @@
86 86
 }
87 87
 .img-preview-container{
88 88
   margin:70rpx 40rpx;
89
-  transition: all 0.3s ease;
90
-  
91
-  .image-section {
92
-    transition: all 0.3s ease;
93
-    margin-bottom: 30rpx;
94
-    
95
-    &.expanded {
96
-      margin-bottom: 40rpx;
97
-    }
98
-    
99
-    .image-container {
100
-      position: relative;
101
-      margin-bottom: 20rpx;
102
-      overflow: hidden;
103
-      border-radius: 10rpx;
104
-      
105
-      .preview-image {
106
-        width: 100%;
107
-        height: 300rpx;
108
-        object-fit: cover;
109
-        transition: all 0.3s ease;
110
-        
111
-        &.zoomed {
112
-          height: 500rpx;
113
-          box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.15);
114
-        }
115
-      }
116
-      
117
-      .crop-overlay {
118
-        position: absolute;
119
-        top: 0;
120
-        left: 0;
121
-        right: 0;
122
-        bottom: 0;
123
-        background-color: rgba(0, 0, 0, 0.5);
124
-        display: flex;
125
-        flex-direction: column;
126
-        justify-content: center;
127
-        align-items: center;
128
-        
129
-        .crop-area {
130
-          position: absolute;
131
-          border: 2rpx solid #409eff;
132
-          background-color: rgba(64, 158, 255, 0.2);
133
-          cursor: move;
134
-          
135
-          .resize-handle {
136
-            position: absolute;
137
-            width: 20rpx;
138
-            height: 20rpx;
139
-            border: 2rpx solid #409eff;
140
-            background-color: #fff;
141
-            border-radius: 50%;
142
-            touch-action: none;
143
-            
144
-            &.top-left {
145
-              top: -10rpx;
146
-              left: -10rpx;
147
-              cursor: nw-resize;
148
-            }
149
-            
150
-            &.top-right {
151
-              top: -10rpx;
152
-              right: -10rpx;
153
-              cursor: ne-resize;
154
-            }
155
-            
156
-            &.bottom-left {
157
-              bottom: -10rpx;
158
-              left: -10rpx;
159
-              cursor: sw-resize;
160
-            }
161
-            
162
-            &.bottom-right {
163
-              bottom: -10rpx;
164
-              right: -10rpx;
165
-              cursor: se-resize;
166
-            }
167
-            
168
-            &.top {
169
-              top: -10rpx;
170
-              left: 50%;
171
-              transform: translateX(-50%);
172
-              cursor: n-resize;
173
-            }
174
-            
175
-            &.bottom {
176
-              bottom: -10rpx;
177
-              left: 50%;
178
-              transform: translateX(-50%);
179
-              cursor: s-resize;
180
-            }
181
-            
182
-            &.left {
183
-              left: -10rpx;
184
-              top: 50%;
185
-              transform: translateY(-50%);
186
-              cursor: w-resize;
187
-            }
188
-            
189
-            &.right {
190
-              right: -10rpx;
191
-              top: 50%;
192
-              transform: translateY(-50%);
193
-              cursor: e-resize;
194
-            }
195
-          }
196
-        }
197
-        
198
-        .crop-controls {
199
-          position: absolute;
200
-          top: 20rpx;
201
-          left: 0;
202
-          right: 0;
203
-          display: flex;
204
-          flex-direction: column;
205
-          align-items: center;
206
-          gap: 10rpx;
207
-          
208
-          .crop-hint {
209
-            color: #fff;
210
-            font-size: 24rpx;
211
-            margin-bottom: 10rpx;
212
-            background-color: rgba(0, 0, 0, 0.5);
213
-            padding: 5rpx 15rpx;
214
-            border-radius: 20rpx;
215
-          }
216
-        }
217
-        
218
-        
219
-      }
220
-      .confirm-crop-btn {
221
-        position: absolute;
222
-        bottom: 20rpx;
223
-        right: 20rpx;
224
-        z-index: 999;
225
-      }
226
-    }
227
-    .img-result-container{
228
-      display: flex;
229
-      justify-content: space-between;
230
-    }
231
-  }
232
-  
233 89
   .img-result-list {
234
-    max-height: 1000rpx;
235
-    transition: all 0.3s ease;
236
-    
237
-    &.compressed {
238
-      max-height: 600rpx;
239
-    }
240
-    
90
+    max-height: 1200rpx;
241 91
     ::v-deep .uni-scroll-view-content{
242 92
       display: grid;
243 93
       grid-template-columns: 1fr 1fr;
@@ -254,20 +104,12 @@
254 104
     border-radius: 10rpx;
255 105
     padding-bottom: 20rpx;
256 106
     text-align: center;
257
-    transition: transform 0.2s ease, box-shadow 0.2s ease;
258
-    
259
-    &:hover {
260
-      transform: translateY(-5rpx);
261
-      box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
262
-    }
263 107
   }
264 108
   
265 109
   .img-result-thumb {
266 110
     width: 100%;
267 111
     height: 250rpx;
268 112
     object-fit: cover;
269
-    border-top-left-radius: 10rpx;
270
-    border-top-right-radius: 10rpx;
271 113
   }
272 114
   
273 115
   .img-result-info {

+ 4 - 1
components/remote-search-select/index.vue

@@ -51,6 +51,8 @@
51 51
                         </view>
52 52
                     </view>
53 53
                 </scroll-view>
54
+                <!-- 空 -->
55
+                <u-empty v-if="imgResults.length === 0"></u-empty>
54 56
             </view>
55 57
 		</u-popup>
56 58
     </view>
@@ -293,7 +295,7 @@ export default {
293 295
                     // const fileName = `crop_${Date.now()}.${this.fileType || 'png'}`
294 296
                     // const file = new File([blob], fileName, { type: blob.type })
295 297
                     // console.log(response,blob,fileName,file)
296
-                    console.log(res)
298
+                    // console.log(res)
297 299
                     this.$emit('select-crop-img', res)
298 300
                 } else {
299 301
                     uni.showToast({
@@ -312,6 +314,7 @@ export default {
312 314
         handleImgClick({ item, index }) {
313 315
             this.activeIndex = index
314 316
             this.currentImg = item
317
+            this.$emit('select-crop-img', item)
315 318
         }
316 319
     }
317 320
 }

+ 1 - 1
pages.json

@@ -198,7 +198,7 @@
198 198
 			}
199 199
 		},
200 200
 		{
201
-			"path": "pages/wareHouse/fieldPermissions",
201
+			"path": "pages/wareHouse/components/fieldPermissions",
202 202
 			"style": {
203 203
 				"navigationBarTitleText": "字段权限",
204 204
 				"enablePullDownRefresh": true,

+ 0 - 2
pages/clue/components/trend.vue

@@ -208,7 +208,6 @@ export default {
208 208
         handleSelectCropImg(file) {
209 209
             this.imgPageNum = 1
210 210
             this.imgTotal = 0
211
-            console.log(file);
212 211
             
213 212
             const data = {
214 213
                 tempFilePaths:[file]
@@ -316,7 +315,6 @@ export default {
316 315
         uploadImage(res) {
317 316
             this.$nextTick(()=>{
318 317
                 this.searchImgInfo = res;
319
-                console.log(res,this.searchImgInfo.tempFilePaths[0]);
320 318
                 uni.$u.api.searchModelByImage(
321 319
                     this.searchImgInfo.tempFilePaths[0],
322 320
                     {

+ 1 - 1
pages/clue/post/index.vue

@@ -77,7 +77,7 @@
77 77
 				<view>发单</view>
78 78
 			</view>
79 79
 		</view>
80
-		<add-inquiry-dialog ref="inquiryDialog" :clueId="clueId" :isClue="true" :editOrAdd="editOrAdd" :editInfo="editInfo" title="询价" @cancel="handleInquiryCancel" :type="1"/>
80
+		<add-inquiry-dialog ref="inquiryDialog" :clueId="clueId" :isShowChart="true" :isClue="true" :editOrAdd="editOrAdd" :editInfo="editInfo" title="询价" @cancel="handleInquiryCancel" :type="1"/>
81 81
 		<!-- 最新跟进记录详情弹窗;关闭时记时间戳,避免蒙层点击冒泡触发详情跳转 -->
82 82
 		<u-popup :show="followPopupVisible" mode="bottom" round="16" @close="onFollowPopupClose"
83 83
 			:closeOnClickOverlay="true" @open="loadFollowList">

+ 137 - 86
pages/wareHouse/components/edit.vue

@@ -26,14 +26,15 @@
26 26
                                 @click="handlePasteRecognition(recognitionContent)"></u-button>
27 27
                         </view>
28 28
                     </u-form-item>
29
-                    <u-form-item :label="'商品图片(' + (formData.goodPicFileList.length || 0) + '张)'" required prop="goodPicFileList" borderBottom>
29
+                    <u-form-item :label="'商品图片('+formData.goodPicFileList.length+'张)'" required prop="goodPicFileList" borderBottom>
30 30
                         <view class="imgs_scroll">
31
-                            <ImgsRowScroll v-if="formData.goodPicFileList.length > 0" :isShowDeleteIcon="true"
31
+                            <DragUpload ref="dragUpload" :images="formData.goodPicFileList" :isDelete="true" :isPreview="true" @imagesChanged="goodPicFileListImagesChanged" @uploadComplete="goodPicFileListUploadComplete"></DragUpload>
32
+                            <!-- <ImgsRowScroll  v-if="formData.goodPicFileList.length > 0" :isShowDeleteIcon="true"
32 33
                                 @deleteImgInfo="getDeleteGoodPicInfo" imgMode="aspectFill" :totalWidth="400"
33 34
                                 :images="formData.goodPicFileList" :previewEnabled="true" :imageWidth="150"
34 35
                                 :imageHeight="150"></ImgsRowScroll>
35 36
                             <u-upload @afterRead="afterReadGoodPic" name="3" multiple :maxCount="9"
36
-                                :previewFullImage="true"></u-upload>
37
+                                :previewFullImage="true"></u-upload> -->
37 38
                         </view>
38 39
                     </u-form-item>
39 40
                     <u-form-item label="商品描述(详细的描述让用户更好的了解您的产品)" required prop="desc" borderBottom>
@@ -85,7 +86,7 @@
85 86
                         <!-- <view class="detail_pic_container"> -->
86 87
                         <!-- <view>
87 88
                                 <text class="tip">视频:</text>
88
-                                <ImgsRowScroll v-if="formData.detailVideoFileList.length > 0" :isShowDeleteIcon="true"
89
+                                <ImgsRowScroll  v-if="formData.detailVideoFileList.length > 0" :isShowDeleteIcon="true"
89 90
                                     @deleteVideoInfo="getDeleteDetailVideoInfo" imgMode="aspectFill" :totalWidth="400"
90 91
                                     :videos="formData.detailVideoFileList" :previewEnabled="true" :imageWidth="150"
91 92
                                     :imageHeight="150" accept="video"></ImgsRowScroll>
@@ -94,11 +95,12 @@
94 95
                         <!-- <view> -->
95 96
                         <!-- <text class="tip">图片:</text> -->
96 97
                         <view class="imgs_scroll">
97
-                            <ImgsRowScroll v-if="formData.detailPicFileList.length > 0" :isShowDeleteIcon="true"
98
+                            <DragUpload ref="dragUpload" :images="formData.detailPicFileList" :isDelete="true" :isPreview="true" @imagesChanged="detailPicFileListImagesChanged" @uploadComplete="detailPicFileListUploadComplete"></DragUpload>
99
+                            <!-- <ImgsRowScroll v-if="formData.detailPicFileList.length > 0" :isShowDeleteIcon="true"
98 100
                                 @deleteImgInfo="getDeleteDetailPicInfo" imgMode="aspectFill" :totalWidth="400"
99 101
                                 :images="formData.detailPicFileList" :previewEnabled="true" :imageWidth="150"
100 102
                                 :imageHeight="150"></ImgsRowScroll>
101
-                            <u-upload @afterRead="afterReadDetailPic" name="1" multiple :maxCount="10"></u-upload>
103
+                            <u-upload @afterRead="afterReadDetailPic" name="1" multiple :maxCount="10"></u-upload> -->
102 104
                         </view>
103 105
                         <!-- </view> -->
104 106
                         <!-- </view> -->
@@ -183,12 +185,13 @@
183 185
                             <u--textarea v-model="formData.recycleBottomDesc" clearable count autoHeight maxlength="250"
184 186
                                 height="100" confirmType="done"></u--textarea>
185 187
                             <view class="imgs_scroll">
186
-                                <ImgsRowScroll v-if="formData.recycleBottomFileList.length > 0" :isShowDeleteIcon="true"
188
+                                <DragUpload ref="dragUpload" :images="formData.recycleBottomFileList" :isDelete="true" :isPreview="true" @imagesChanged="recycleBottomFileListImagesChanged" @uploadComplete="recycleBottomFileListUploadComplete"></DragUpload>
189
+                                <!-- <ImgsRowScroll  v-if="formData.recycleBottomFileList.length > 0" :isShowDeleteIcon="true"
187 190
                                     @deleteImgInfo="getDeleteRecycleBottomPicInfo" imgMode="aspectFill"
188 191
                                     :totalWidth="400" :images="formData.recycleBottomFileList" :previewEnabled="true"
189 192
                                     :imageWidth="150" :imageHeight="150"></ImgsRowScroll>
190
-                                <u-upload @afterRead="afterReadRecycleBottom" name="1" multiple :maxCount="1"
191
-                                    accept="image"></u-upload>
193
+                                <u-upload @afterRead="afterReadRecycleBottom" name="1" multiple :maxCount="10"
194
+                                    accept="image"></u-upload> -->
192 195
                             </view>
193 196
                         </view>
194 197
                     </u-form-item>
@@ -222,12 +225,13 @@
222 225
                     </u-form-item>
223 226
                     <u-form-item :label="'保卡图片或独立编码照片留底(' + (formData.productCardPicFileList.length || 0) + '张)'" borderBottom>
224 227
                         <view class="imgs_scroll">
225
-                            <ImgsRowScroll v-if="formData.productCardPicFileList.length > 0" :isShowDeleteIcon="true"
228
+                            <DragUpload ref="dragUpload" :images="formData.productCardPicFileList" :isDelete="true" :isPreview="true" @imagesChanged="productCardPicFileListImagesChanged" @uploadComplete="productCardPicFileListUploadComplete"></DragUpload>
229
+                            <!-- <ImgsRowScroll  v-if="formData.productCardPicFileList.length > 0" :isShowDeleteIcon="true"
226 230
                                 @deleteImgInfo="getDeleteProductCardPicInfo" imgMode="aspectFill" :totalWidth="400"
227 231
                                 :images="formData.productCardPicFileList" :previewEnabled="true" :imageWidth="150"
228 232
                                 :imageHeight="150"></ImgsRowScroll>
229
-                            <u-upload @afterRead="afterReadProductCardPic" name="3" multiple :maxCount="9"
230
-                                :previewFullImage="true"></u-upload>
233
+                            <u-upload @afterRead="afterReadProductCardPic" name="3" multiple :maxCount="10"
234
+                                :previewFullImage="true"></u-upload> -->
231 235
                         </view>
232 236
                     </u-form-item>
233 237
                     <u-form-item label="商品标签" class="u-form-item-row" borderBottom>
@@ -242,12 +246,13 @@
242 246
                             <u--textarea v-model="formData.productDesc" clearable count autoHeight maxlength="250"
243 247
                                 height="100" confirmType="done"></u--textarea>
244 248
                             <view class="imgs_scroll">
245
-                                <ImgsRowScroll v-if="formData.productDescPicFileList.length > 0"
249
+                                <DragUpload ref="dragUpload" :images="formData.productDescPicFileList" :isDelete="true" :isPreview="true" @imagesChanged="productDescPicFileListImagesChanged" @uploadComplete="productDescPicFileListUploadComplete"></DragUpload>
250
+                                <!-- <ImgsRowScroll  v-if="formData.productDescPicFileList.length > 0"
246 251
                                     :isShowDeleteIcon="true" @deleteImgInfo="getDeleteProductDescPicInfo"
247 252
                                     imgMode="aspectFill" :totalWidth="400" :images="formData.productDescPicFileList"
248 253
                                     :previewEnabled="true" :imageWidth="150" :imageHeight="150"></ImgsRowScroll>
249
-                                <u-upload @afterRead="afterReadProductDescPic" name="1" multiple :maxCount="1"
250
-                                    accept="image"></u-upload>
254
+                                <u-upload @afterRead="afterReadProductDescPic" name="1" multiple :maxCount="10"
255
+                                    accept="image"></u-upload> -->
251 256
                             </view>
252 257
                         </view>
253 258
                     </u-form-item>
@@ -271,6 +276,7 @@ import TabSelect from '@/components/custom-tab-select/index.vue'
271 276
 import Cell from '@/components/custom-cell/index.vue'
272 277
 import BrandList from '@/components/brand-list/index.vue'
273 278
 import ImgsRowScroll from '@/components/imgs-row-scroll/index.vue'
279
+import DragUpload from '@/components/drag-upload/index.vue'
274 280
 import PersonPicker from '@/components/person-picker/index.vue'
275 281
 import { permissionCheck,getRoles } from '@/utils/util.js'
276 282
 import moreInfo from './moreInfo.vue'
@@ -282,7 +288,8 @@ export default {
282 288
         BrandList,
283 289
         ImgsRowScroll,
284 290
         PersonPicker,
285
-        moreInfo
291
+        moreInfo,
292
+        DragUpload
286 293
     },
287 294
     data() {
288 295
         return {
@@ -522,6 +529,8 @@ export default {
522 529
                             uni.$u.toast('操作成功');
523 530
                             if (data.continuousWarehousing == '0') {
524 531
                                 setTimeout(() => {
532
+                                    // 发送事件通知列表页刷新数据
533
+                                    uni.$emit('warehouse-data-updated');
525 534
                                     uni.navigateBack({
526 535
                                         delta: 1
527 536
                                     });
@@ -537,6 +546,8 @@ export default {
537 546
                             uni.$u.toast('操作成功');
538 547
                             if (data.continuousWarehousing == '0') {
539 548
                                 setTimeout(() => {
549
+                                    // 发送事件通知列表页刷新数据
550
+                                    uni.$emit('warehouse-data-updated');
540 551
                                     uni.navigateBack({
541 552
                                         delta: 1
542 553
                                     });
@@ -716,81 +727,121 @@ export default {
716 727
             this.formData.recyclePerson = info.label;
717 728
             this.formData.recyclePersonId = info.id;
718 729
         },
719
-        // 新增商品图片
720
-        async afterReadGoodPic(event) {
721
-            event.file.forEach(item => {
722
-                uni.$u.api.uploadFile(item.url).then((res) => {
723
-                    this.formData.goodPicFileList.push(res.data.url);
724
-                    uni.$u.toast("文件上传成功");
725
-                }).catch(() => {
726
-                    uni.$u.toast("上传文件失败");
727
-                })
728
-            })
730
+        // 商品图片拖拽完成
731
+        goodPicFileListImagesChanged(info) {
732
+            this.formData.goodPicFileList = info
729 733
         },
730
-        // 获取删除商品图片信息
731
-        getDeleteGoodPicInfo(info) {
732
-            this.formData.goodPicFileList = info.newImages
733
-        },
734
-        // 获取删除细节图片信息
735
-        getDeleteDetailPicInfo(info) {
736
-            this.formData.detailPicFileList = info.newImages
737
-        },
738
-        // 新增细节图片
739
-        async afterReadDetailPic(event) {
740
-            event.file.forEach(item => {
741
-                uni.$u.api.uploadFile(item.url).then((res) => {
742
-                    this.formData.detailPicFileList.push(res.data.url);
743
-                    uni.$u.toast("文件上传成功");
744
-                }).catch(() => {
745
-                    uni.$u.toast("上传文件失败");
746
-                })
747
-            })
734
+        // 商品图片上传完成
735
+        goodPicFileListUploadComplete(info) {
736
+            this.formData.goodPicFileList = info
748 737
         },
749
-        // 获取删除回收留底图信息
750
-        getDeleteRecycleBottomPicInfo(info) {
751
-            this.formData.recycleBottomFileList = info.newImages
752
-        },
753
-        // 新增回收留底图
754
-        async afterReadRecycleBottom(event) {
755
-            event.file.forEach(item => {
756
-                uni.$u.api.uploadFile(item.url).then((res) => {
757
-                    this.formData.recycleBottomFileList.push(res.data.url);
758
-                    uni.$u.toast("文件上传成功");
759
-                }).catch(() => {
760
-                    uni.$u.toast("上传文件失败");
761
-                })
762
-            })
738
+        // 细节图片拖拽完成
739
+        detailPicFileListImagesChanged(info) {
740
+            this.formData.detailPicFileList = info
763 741
         },
764
-        // 删除商品保卡图片或独立编码照片留底
765
-        getDeleteProductCardPicInfo(info) {
766
-            this.formData.productCardPicFileList = info.newImages
767
-        },
768
-        // 新增商品保卡图片或独立编码照片留底
769
-        async afterReadProductCardPic(event) {
770
-            event.file.forEach(item => {
771
-                uni.$u.api.uploadFile(item.url).then((res) => {
772
-                    this.formData.productCardPicFileList.push(res.data.url);
773
-                    uni.$u.toast("文件上传成功");
774
-                }).catch(() => {
775
-                    uni.$u.toast("上传文件失败");
776
-                })
777
-            })
742
+        // 细节图片上传完成
743
+        detailPicFileListUploadComplete(info) {
744
+            this.formData.detailPicFileList = info
778 745
         },
779
-        // 获取删除商品备注图片信息
780
-        getDeleteProductDescPicInfo(info) {
781
-            this.formData.productDescPicFileList = info.newImages
782
-        },
783
-        // 新增商品备注图片
784
-        async afterReadProductDescPic(event) {
785
-            event.file.forEach(item => {
786
-                uni.$u.api.uploadFile(item.url).then((res) => {
787
-                    this.formData.productDescPicFileList.push(res.data.url);
788
-                    uni.$u.toast("文件上传成功");
789
-                }).catch(() => {
790
-                    uni.$u.toast("上传文件失败");
791
-                })
792
-            })
746
+        // 回收留底图拖拽完成
747
+        recycleBottomFileListImagesChanged(info) {
748
+            this.formData.recycleBottomFileList = info
749
+        },
750
+        // 回收留底图上传完成
751
+        recycleBottomFileListUploadComplete(info) {
752
+            this.formData.recycleBottomFileList = info
753
+        },
754
+        // 商品保卡图片拖拽完成
755
+        productCardPicFileListImagesChanged(info) {
756
+            this.formData.productCardPicFileList = info
757
+        },
758
+        // 商品保卡图片上传完成
759
+        productCardPicFileListUploadComplete(info) {
760
+            this.formData.productCardPicFileList = info
793 761
         },
762
+        // 商品描述图片拖拽完成
763
+        productDescPicFileListImagesChanged(info) {
764
+            this.formData.productDescPicFileList = info
765
+        },
766
+        // 商品描述图片上传完成
767
+        productDescPicFileListUploadComplete(info) {
768
+            this.formData.productDescPicFileList = info
769
+        },
770
+        // 新增商品图片
771
+        // async afterReadGoodPic(event) {
772
+        //     event.file.forEach(item => {
773
+        //         uni.$u.api.uploadFile(item.url).then((res) => {
774
+        //             this.formData.goodPicFileList.push(res.data.url);
775
+        //             uni.$u.toast("文件上传成功");
776
+        //         }).catch(() => {
777
+        //             uni.$u.toast("上传文件失败");
778
+        //         })
779
+        //     })
780
+        // },
781
+        // // 获取删除商品图片信息
782
+        // getDeleteGoodPicInfo(info) {
783
+        //     this.formData.goodPicFileList = info.newImages
784
+        // },
785
+        // // 获取删除细节图片信息
786
+        // getDeleteDetailPicInfo(info) {
787
+        //     this.formData.detailPicFileList = info
788
+        // },
789
+        // // 新增细节图片
790
+        // async afterReadDetailPic(event) {
791
+        //     event.file.forEach(item => {
792
+        //         uni.$u.api.uploadFile(item.url).then((res) => {
793
+        //             this.formData.detailPicFileList.push(res.data.url);
794
+        //             uni.$u.toast("文件上传成功");
795
+        //         }).catch(() => {
796
+        //             uni.$u.toast("上传文件失败");
797
+        //         })
798
+        //     })
799
+        // },
800
+        // 获取删除回收留底图信息
801
+        // getDeleteRecycleBottomPicInfo(info) {
802
+        //     this.formData.recycleBottomFileList = info.newImages
803
+        // },
804
+        // // 新增回收留底图
805
+        // async afterReadRecycleBottom(event) {
806
+        //     event.file.forEach(item => {
807
+        //         uni.$u.api.uploadFile(item.url).then((res) => {
808
+        //             this.formData.recycleBottomFileList.push(res.data.url);
809
+        //             uni.$u.toast("文件上传成功");
810
+        //         }).catch(() => {
811
+        //             uni.$u.toast("上传文件失败");
812
+        //         })
813
+        //     })
814
+        // },
815
+        // // 删除商品保卡图片或独立编码照片留底
816
+        // getDeleteProductCardPicInfo(info) {
817
+        //     this.formData.productCardPicFileList = info.newImages
818
+        // },
819
+        // // 新增商品保卡图片或独立编码照片留底
820
+        // async afterReadProductCardPic(event) {
821
+        //     event.file.forEach(item => {
822
+        //         uni.$u.api.uploadFile(item.url).then((res) => {
823
+        //             this.formData.productCardPicFileList.push(res.data.url);
824
+        //             uni.$u.toast("文件上传成功");
825
+        //         }).catch(() => {
826
+        //             uni.$u.toast("上传文件失败");
827
+        //         })
828
+        //     })
829
+        // },
830
+        // // 获取删除商品备注图片信息
831
+        // getDeleteProductDescPicInfo(info) {
832
+        //     this.formData.productDescPicFileList = info.newImages
833
+        // },
834
+        // // 新增商品备注图片
835
+        // async afterReadProductDescPic(event) {
836
+        //     event.file.forEach(item => {
837
+        //         uni.$u.api.uploadFile(item.url).then((res) => {
838
+        //             this.formData.productDescPicFileList.push(res.data.url);
839
+        //             uni.$u.toast("文件上传成功");
840
+        //         }).catch(() => {
841
+        //             uni.$u.toast("上传文件失败");
842
+        //         })
843
+        //     })
844
+        // },
794 845
         async handlePasteRecognition(text) {
795 846
             // 品牌:浪琴
796 847
             // 来源:【麒麟】私信-杰3-3

+ 9 - 5
pages/wareHouse/fieldPermissions.vue

@@ -1,10 +1,10 @@
1 1
 <template>
2 2
 	<view class="page">
3
-		<u-navbar class="nav-bar" title="字段权限配置" :autoBack="true" :placeholder="true" v-hideNav></u-navbar>
3
+		<u-navbar class="nav-bar" title="仓库字段权限配置" :autoBack="true" :placeholder="true" v-hideNav></u-navbar>
4 4
 		<view class="content">
5 5
 			<view class="tip-card">
6 6
 				<u-icon name="setting" size="18" color="#108cff"></u-icon>
7
-				<text class="tip-text">为指定角色配置仓库各字段的「可」「可编辑」权限,保存后该角色用户将按此配置在列表/详情中看到并可编辑对应字段。</text>
7
+				<text class="tip-text">为指定角色配置仓库各字段的「可查看」「可编辑」权限,保存后该角色用户将按此配置在列表/详情中看到并可编辑对应字段。</text>
8 8
 			</view>
9 9
 
10 10
 			<!-- 选择角色 -->
@@ -29,8 +29,8 @@
29 29
 					</view>
30 30
 				</view>
31 31
 				<view class="btn-row">
32
-					<u-button type="primary" size="small" :loading="loadConfigLoading" @click="loadConfig">加载配置</u-button>
33 32
 					<u-button type="error" plain size="small" :disabled="!currentRoleId" @click="clearConfig">清空该角色配置</u-button>
33
+					<u-button type="primary" size="small" :loading="loadConfigLoading" @click="loadConfig">加载配置</u-button>
34 34
 				</view>
35 35
 			</view>
36 36
 
@@ -53,7 +53,7 @@
53 53
 							</view>
54 54
 							<view class="field-switches">
55 55
 								<view class="switch-cell">
56
-									<text class="switch-label"></text>
56
+									<text class="switch-label">查看</text>
57 57
 									<u-switch v-model="item.read" size="20" active-color="#108cff"></u-switch>
58 58
 								</view>
59 59
 								<view class="switch-cell">
@@ -284,6 +284,10 @@ export default {
284 284
 	.section-title {
285 285
 		margin-bottom: 0;
286 286
 	}
287
+	.u-button {
288
+		width:auto;
289
+		margin: 0;
290
+	}
287 291
 }
288 292
 
289 293
 .role-section {
@@ -325,7 +329,7 @@ export default {
325 329
 	.btn-row {
326 330
 		display: flex;
327 331
 		gap: 20rpx;
328
-		flex-wrap: wrap;
332
+		// flex-wrap: wrap;
329 333
 	}
330 334
 }
331 335
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 32 - 4
pages/wareHouse/index.vue


+ 14 - 4
pages/wareHouse/styles/index.scss

@@ -112,9 +112,8 @@
112 112
 
113 113
 /* 搜索框区域 */
114 114
 .search-wrapper {
115
-  padding: 8rpx 15rpx;
115
+  padding: 0 15rpx;
116 116
   height: 80rpx;
117
-  padding-bottom: 20rpx;
118 117
   display: flex;
119 118
   justify-content: space-between;
120 119
   align-items: center;
@@ -147,8 +146,7 @@
147 146
 
148 147
 /* 分类标签 */
149 148
 .category-tabs-wrap {
150
-  padding: 8rpx 15rpx;
151
-  margin-bottom: 20rpx;
149
+  padding: 0 15rpx;
152 150
   background: #ffffff !important;
153 151
 
154 152
   .u-tabs-custom {
@@ -172,6 +170,14 @@
172 170
       display: none;
173 171
     }
174 172
   }
173
+
174
+  ::v-deep .u-tabs__wrapper__nav__item{
175
+    height: 70rpx !important;
176
+  }
177
+}
178
+
179
+::v-deep .u-notice-bar{
180
+  flex:auto;
175 181
 }
176 182
 
177 183
 /* 筛选栏 */
@@ -513,3 +519,7 @@
513 519
     transform: scale(0.95);
514 520
   }
515 521
 }
522
+
523
+.custom-notice-bar {
524
+  flex: none;
525
+}