@alu008/test_yuanqikaixiang 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/App.vue +294 -0
  2. package/Local/en.json +3 -0
  3. package/Local/indian.json +3 -0
  4. package/Local/zh-Hans.json +3 -0
  5. package/Local/zh-Hant.json +3 -0
  6. package/README.md +1 -0
  7. package/androidPrivacy.json +28 -0
  8. package/components/ball/ball.vue +230 -0
  9. package/components/cardDetails/cardDetails.vue +273 -0
  10. package/components/confirmModal/confirmModal.vue +125 -0
  11. package/components/fillInfo/fillInfo.vue +255 -0
  12. package/components/header/header.vue +92 -0
  13. package/components/selectAddress/selectAddress.vue +156 -0
  14. package/components/signDetail/signDetail.vue +33 -0
  15. package/components/skeleton/skeleton.vue +62 -0
  16. package/index.html +20 -0
  17. package/index.template.html +35 -0
  18. package/jsconfig.json +9 -0
  19. package/main.js +48 -0
  20. package/manifest.json +159 -0
  21. package/package.json +14 -0
  22. package/pages/index/index.vue +5421 -0
  23. package/pages.json +173 -0
  24. package/project.config.json +25 -0
  25. package/project.private.config.json +14 -0
  26. package/static/fonts/Alibaba-PuHuiTi-Bold.ttf +0 -0
  27. package/static/fonts/Alibaba-PuHuiTi-Medium.ttf +0 -0
  28. package/static/fonts/Alibaba-PuHuiTi-Regular.ttf +0 -0
  29. package/static/fonts/fxlh.ttf +0 -0
  30. package/static/img/R.png +0 -0
  31. package/static/img/SR.png +0 -0
  32. package/static/img/SSR.png +0 -0
  33. package/static/img/bottomBgc1.png +0 -0
  34. package/static/img/centerBgc.png +0 -0
  35. package/static/img/goldBgc.png +0 -0
  36. package/static/img/goldText.png +0 -0
  37. package/static/img/home/calendar/bgc0.png +0 -0
  38. package/static/img/home/calendar/bgc1.png +0 -0
  39. package/static/img/home/calendar/bgc2.png +0 -0
  40. package/static/img/home/calendar/bgc3.png +0 -0
  41. package/static/img/home/calendar/progress0.png +0 -0
  42. package/static/img/home/calendar/progress1.png +0 -0
  43. package/static/img/home/calendar/progress2.png +0 -0
  44. package/static/img/home/calendar/progress3.png +0 -0
  45. package/static/img/kuang.gif +0 -0
  46. package/static/img/luckyBgc.png +0 -0
  47. package/static/img/lucyText.png +0 -0
  48. package/static/img/top_Bgc.png +0 -0
  49. package/subpackages/article/article.vue +64 -0
  50. package/subpackages/confirmSendLogistics/confirmSendLogistics.vue +1035 -0
  51. package/subpackages/coupon/coupon.vue +276 -0
  52. package/subpackages/fragment/fragment.vue +1592 -0
  53. package/subpackages/myAddress/myAddress.vue +656 -0
  54. package/subpackages/myCards/myCards.vue +1250 -0
  55. package/subpackages/myOrder/myOrder.vue +779 -0
  56. package/subpackages/myOrderDetail/myOrderDetail.vue +659 -0
  57. package/subpackages/poster/poster.vue +130 -0
  58. package/subpackages/selectCoupon/selectCoupon.vue +251 -0
  59. package/subpackages/sendLogistics/sendLogistics.vue +1097 -0
  60. package/subpackages/vote/vote.vue +877 -0
  61. package/uni.promisify.adaptor.js +10 -0
  62. package/uni.scss +114 -0
  63. package/uni_modules/qf-image-cropper/changelog.md +72 -0
  64. package/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.render.js +855 -0
  65. package/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue +749 -0
  66. package/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.wxs +727 -0
  67. package/uni_modules/qf-image-cropper/package.json +81 -0
  68. package/uni_modules/qf-image-cropper/readme.md +97 -0
  69. package/uni_modules/uni-data-select/changelog.md +51 -0
  70. package/uni_modules/uni-data-select/components/uni-data-select/uni-data-select.vue +837 -0
  71. package/uni_modules/uni-data-select/package.json +106 -0
  72. package/uni_modules/uni-data-select/readme.md +8 -0
  73. package/uni_modules/uni-icons/changelog.md +44 -0
  74. package/uni_modules/uni-icons/components/uni-icons/uni-icons.uvue +91 -0
  75. package/uni_modules/uni-icons/components/uni-icons/uni-icons.vue +110 -0
  76. package/uni_modules/uni-icons/components/uni-icons/uniicons.css +664 -0
  77. package/uni_modules/uni-icons/components/uni-icons/uniicons.ttf +0 -0
  78. package/uni_modules/uni-icons/components/uni-icons/uniicons_file.ts +664 -0
  79. package/uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js +649 -0
  80. package/uni_modules/uni-icons/package.json +111 -0
  81. package/uni_modules/uni-icons/readme.md +8 -0
  82. package/uni_modules/uni-load-more/changelog.md +23 -0
  83. package/uni_modules/uni-load-more/components/uni-load-more/i18n/en.json +5 -0
  84. package/uni_modules/uni-load-more/components/uni-load-more/i18n/index.js +8 -0
  85. package/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hans.json +5 -0
  86. package/uni_modules/uni-load-more/components/uni-load-more/i18n/zh-Hant.json +5 -0
  87. package/uni_modules/uni-load-more/components/uni-load-more/uni-load-more.vue +404 -0
  88. package/uni_modules/uni-load-more/package.json +105 -0
  89. package/uni_modules/uni-load-more/readme.md +14 -0
  90. package/uni_modules/uni-scss/changelog.md +8 -0
  91. package/uni_modules/uni-scss/index.scss +1 -0
  92. package/uni_modules/uni-scss/package.json +82 -0
  93. package/uni_modules/uni-scss/readme.md +4 -0
  94. package/uni_modules/uni-scss/styles/index.scss +7 -0
  95. package/uni_modules/uni-scss/styles/setting/_border.scss +3 -0
  96. package/uni_modules/uni-scss/styles/setting/_color.scss +66 -0
  97. package/uni_modules/uni-scss/styles/setting/_radius.scss +55 -0
  98. package/uni_modules/uni-scss/styles/setting/_space.scss +56 -0
  99. package/uni_modules/uni-scss/styles/setting/_styles.scss +167 -0
  100. package/uni_modules/uni-scss/styles/setting/_text.scss +24 -0
  101. package/uni_modules/uni-scss/styles/setting/_variables.scss +146 -0
  102. package/uni_modules/uni-scss/styles/tools/functions.scss +19 -0
  103. package/uni_modules/uni-scss/theme.scss +31 -0
  104. package/uni_modules/uni-scss/variables.scss +62 -0
  105. package/utils/addressData.js +6042 -0
  106. package/utils/api.js +160 -0
  107. package/utils/fetch.js +548 -0
  108. package/utils/index.js +994 -0
  109. package/utils/navigator.js +17 -0
  110. package/utils/request.js +162 -0
@@ -0,0 +1,749 @@
1
+ <template>
2
+ <view class="image-cropper" :style="{ zIndex }" @wheel="cropper.mousewheel">
3
+ <canvas v-if="use2d" type="2d" id="imgCanvas" class="img-canvas" :style="{
4
+ width: `${canvansWidth}px`,
5
+ height: `${canvansHeight}px`
6
+ }"></canvas>
7
+ <canvas v-else id="imgCanvas" canvas-id="imgCanvas" class="img-canvas" :style="{
8
+ width: `${canvansWidth}px`,
9
+ height: `${canvansHeight}px`
10
+ }"></canvas>
11
+ <view id="pic-preview" class="pic-preview" :change:init="cropper.initObserver" :init="initData" @touchstart="cropper.touchstart" @touchmove="cropper.touchmove" @touchend="cropper.touchend">
12
+ <image v-if="imgSrc" id="crop-image" class="crop-image" :style="cropper.imageStyles" :src="imgSrc" webp></image>
13
+ <view v-for="(item, index) in maskList" :key="item.id" :id="item.id" class="crop-mask-block" :style="cropper.maskStylesList[index]"></view>
14
+ <view v-if="showBorder" id="crop-border" class="crop-border" :style="cropper.borderStyles"></view>
15
+ <view v-if="radius > 0" id="crop-circle-box" class="crop-circle-box" :style="cropper.circleBoxStyles">
16
+ <view class="crop-circle" id="crop-circle" :style="cropper.circleStyles"></view>
17
+ </view>
18
+ <block v-if="showGrid">
19
+ <view v-for="(item, index) in gridList" :key="item.id" :id="item.id" class="crop-grid" :style="cropper.gridStylesList[index]"></view>
20
+ </block>
21
+ <block v-if="showAngle">
22
+ <view v-for="(item, index) in angleList" :key="item.id" :id="item.id" class="crop-angle" :style="cropper.angleStylesList[index]">
23
+ <view :style="[{
24
+ width: `${angleSize}px`,
25
+ height: `${angleSize}px`
26
+ }]"></view>
27
+ </view>
28
+ </block>
29
+ </view>
30
+ <slot />
31
+ <view class="fixed-bottom safe-area-inset-bottom" :style="{ zIndex: initData.area.zIndex + 99 }">
32
+ <view v-if="(rotatable || reverseRotatable) && !!imgSrc" class="action-bar">
33
+ <view v-if="reverseRotatable" class="rotate-icon" @click="cropper.rotateImage270"></view>
34
+ <view v-if="rotatable" class="rotate-icon is-reverse" @click="cropper.rotateImage90"></view>
35
+ </view>
36
+ <view v-if="!choosable" class="choose-btn" @click="cropClick">确定</view>
37
+ <block v-else-if="!!imgSrc">
38
+ <view class="rechoose" @click="chooseImage">重选</view>
39
+ <button class="button" size="mini" @click="cropClick">确定</button>
40
+ </block>
41
+ <view v-else class="choose-btn" @click="chooseImage">选择图片</view>
42
+ </view>
43
+ </view>
44
+ </template>
45
+
46
+ <!-- #ifdef APP-VUE -->
47
+ <script module="cropper" lang="renderjs">
48
+ import cropper from './qf-image-cropper.render.js';
49
+ // vue3 app renderjs中条件编译无效
50
+ cropper.setPlatform('APP');
51
+ export default {
52
+ mixins: [ cropper ]
53
+ }
54
+ </script>
55
+ <!-- #endif -->
56
+ <!-- #ifdef H5 -->
57
+ <script module="cropper" lang="renderjs">
58
+ import cropper from './qf-image-cropper.render.js';
59
+ export default {
60
+ mixins: [ cropper ]
61
+ }
62
+ </script>
63
+ <!-- #endif -->
64
+ <!-- #ifdef MP-WEIXIN || MP-QQ -->
65
+ <script module="cropper" lang="wxs" src="./qf-image-cropper.wxs"></script>
66
+ <!-- #endif -->
67
+ <script>
68
+ /** 裁剪区域最大宽高所占屏幕宽度百分比 */
69
+ const AREA_SIZE = 75;
70
+ /** 图片默认宽高 */
71
+ const IMG_SIZE = 300;
72
+
73
+ export default {
74
+ name:"qf-image-cropper",
75
+ // #ifdef MP-WEIXIN
76
+ options: {
77
+ // 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响
78
+ styleIsolation: "isolated"
79
+ },
80
+ // #endif
81
+ props: {
82
+ /** 图片资源地址 */
83
+ src: {
84
+ type: String,
85
+ default: ''
86
+ },
87
+ /** 裁剪宽度,有些平台或设备对于canvas的尺寸有限制,过大可能会导致无法正常绘制 */
88
+ width: {
89
+ type: Number,
90
+ default: IMG_SIZE
91
+ },
92
+ /** 裁剪高度,有些平台或设备对于canvas的尺寸有限制,过大可能会导致无法正常绘制 */
93
+ height: {
94
+ type: Number,
95
+ default: IMG_SIZE
96
+ },
97
+ /** 是否绘制裁剪区域边框 */
98
+ showBorder: {
99
+ type: Boolean,
100
+ default: true
101
+ },
102
+ /** 是否绘制裁剪区域网格参考线 */
103
+ showGrid: {
104
+ type: Boolean,
105
+ default: true
106
+ },
107
+ /** 是否展示四个支持伸缩的角 */
108
+ showAngle: {
109
+ type: Boolean,
110
+ default: true
111
+ },
112
+ /** 裁剪区域最小缩放倍数 */
113
+ areaScale: {
114
+ type: Number,
115
+ default: 0.3
116
+ },
117
+ /** 图片最小缩放倍数 */
118
+ minScale: {
119
+ type: Number,
120
+ default: 1
121
+ },
122
+ /** 图片最大缩放倍数 */
123
+ maxScale: {
124
+ type: Number,
125
+ default: 5
126
+ },
127
+ /** 检查图片位置是否超出裁剪边界,如果超出则会矫正位置 */
128
+ checkRange: {
129
+ type: Boolean,
130
+ default: true
131
+ },
132
+ /** 生成图片背景色:如果裁剪区域没有完全包含在图片中时,不设置该属性生成图片存在一定的透明块 */
133
+ backgroundColor: {
134
+ type: String
135
+ },
136
+ /** 是否有回弹效果:当 checkRange 为 true 时有效,拖动时可以拖出边界,释放时会弹回边界 */
137
+ bounce: {
138
+ type: Boolean,
139
+ default: true
140
+ },
141
+ /** 是否支持翻转 */
142
+ rotatable: {
143
+ type: Boolean,
144
+ default: true
145
+ },
146
+ /** 是否支持逆向翻转 */
147
+ reverseRotatable: {
148
+ type: Boolean,
149
+ default: false
150
+ },
151
+ /** 是否支持从本地选择素材 */
152
+ choosable: {
153
+ type: Boolean,
154
+ default: true
155
+ },
156
+ /** 是否开启硬件加速,图片缩放过程中如果出现元素的“留影”或“重影”效果,可通过该方式解决或减轻这一问题 */
157
+ gpu: {
158
+ type: Boolean,
159
+ default: false
160
+ },
161
+ /** 四个角尺寸,单位px */
162
+ angleSize: {
163
+ type: Number,
164
+ default: 20
165
+ },
166
+ /** 四个角边框宽度,单位px */
167
+ angleBorderWidth: {
168
+ type: Number,
169
+ default: 2
170
+ },
171
+ zIndex: {
172
+ type: [Number, String]
173
+ },
174
+ /** 裁剪图片圆角半径,单位px */
175
+ radius: {
176
+ type: Number,
177
+ default: 0
178
+ },
179
+ /** 生成文件的类型,只支持 'jpg' 或 'png'。默认为 'png' */
180
+ fileType: {
181
+ type: String,
182
+ default: 'png'
183
+ },
184
+ /**
185
+ * 图片从绘制到生成所需时间,单位ms
186
+ * 微信小程序平台使用 `Canvas 2D` 绘制时有效
187
+ * 如绘制大图或出现裁剪图片空白等情况应适当调大该值,因 `Canvas 2d` 采用同步绘制,需自己把控绘制完成时间
188
+ */
189
+ delay: {
190
+ type: Number,
191
+ default: 1000
192
+ },
193
+ // #ifdef H5
194
+ /**
195
+ * 页面是否是原生标题栏
196
+ * H5平台当 showAngle 为 true 时,使用插件的页面在 `page.json` 中配置了 "navigationStyle": "custom" 时,必须将此值设为 false ,否则四个可拉伸角的触发位置会有偏差。
197
+ * 注:因H5平台的窗口高度是包含标题栏的,而屏幕触摸点的坐标是不包含的
198
+ */
199
+ navigation: {
200
+ type: Boolean,
201
+ default: true
202
+ }
203
+ // #endif
204
+ },
205
+ emits: ["crop"],
206
+ data() {
207
+ return {
208
+ // 用不同 id 使 v-for key 不重复
209
+ maskList: [
210
+ { id: 'crop-mask-block-1' },
211
+ { id: 'crop-mask-block-2' },
212
+ { id: 'crop-mask-block-3' },
213
+ { id: 'crop-mask-block-4' },
214
+ ],
215
+ gridList: [
216
+ { id: 'crop-grid-1' },
217
+ { id: 'crop-grid-2' },
218
+ { id: 'crop-grid-3' },
219
+ { id: 'crop-grid-4' },
220
+ ],
221
+ angleList: [
222
+ { id: 'crop-angle-1' },
223
+ { id: 'crop-angle-2' },
224
+ { id: 'crop-angle-3' },
225
+ { id: 'crop-angle-4' },
226
+ ],
227
+ /** 本地缓存的图片路径 */
228
+ imgSrc: '',
229
+ /** 图片的裁剪宽度 */
230
+ imgWidth: IMG_SIZE,
231
+ /** 图片的裁剪高度 */
232
+ imgHeight: IMG_SIZE,
233
+ /** 裁剪区域最大宽度所占屏幕宽度百分比 */
234
+ widthPercent: AREA_SIZE,
235
+ /** 裁剪区域最大高度所占屏幕宽度百分比 */
236
+ heightPercent: AREA_SIZE,
237
+ /** 裁剪区域布局信息 */
238
+ area: {},
239
+ /** 未被缩放过的图片宽 */
240
+ oldWidth: 0,
241
+ /** 未被缩放过的图片高 */
242
+ oldHeight: 0,
243
+ /** 系统信息 */
244
+ sys: uni.getSystemInfoSync(),
245
+ scaleWidth: 0,
246
+ scaleHeight: 0,
247
+ rotate: 0,
248
+ offsetX: 0,
249
+ offsetY: 0,
250
+ use2d: false,
251
+ canvansWidth: 0,
252
+ canvansHeight: 0,
253
+ // imageStyles: {},
254
+ // maskStylesList: [{}, {}, {}, {}],
255
+ // borderStyles: {},
256
+ // gridStylesList: [{}, {}, {}, {}],
257
+ // angleStylesList: [{}, {}, {}, {}],
258
+ // circleBoxStyles: {},
259
+ // circleStyles: {},
260
+ }
261
+ },
262
+ computed: {
263
+ initData() {
264
+ // console.log('initData')
265
+ return {
266
+ timestamp: new Date().getTime(),
267
+ area: {
268
+ ...this.area,
269
+ bounce: this.bounce,
270
+ showBorder: this.showBorder,
271
+ showGrid: this.showGrid,
272
+ showAngle: this.showAngle,
273
+ angleSize: this.angleSize,
274
+ angleBorderWidth: this.angleBorderWidth,
275
+ minScale: this.areaScale,
276
+ widthPercent: this.widthPercent,
277
+ heightPercent: this.heightPercent,
278
+ radius: this.radius,
279
+ checkRange: this.checkRange,
280
+ zIndex: +this.zIndex || 0,
281
+ },
282
+ sys: this.sys,
283
+ img: {
284
+ minScale: this.minScale,
285
+ maxScale: this.maxScale,
286
+ src: this.imgSrc,
287
+ width: this.oldWidth,
288
+ height: this.oldHeight,
289
+ oldWidth: this.oldWidth,
290
+ oldHeight: this.oldHeight,
291
+ gpu: this.gpu,
292
+ }
293
+ }
294
+ },
295
+ imgProps() {
296
+ return {
297
+ width: this.width,
298
+ height: this.height,
299
+ src: this.src,
300
+ }
301
+ }
302
+ },
303
+ watch: {
304
+ imgProps: {
305
+ handler(val, oldVal) {
306
+ // 自定义裁剪尺,示例如下:
307
+ this.imgWidth = Number(val.width) || IMG_SIZE;
308
+ this.imgHeight = Number(val.height) || IMG_SIZE;
309
+ let use2d = true;
310
+ // #ifndef MP-WEIXIN
311
+ use2d = false;
312
+ // #endif
313
+ // if(use2d && (this.imgWidth > 1365 || this.imgHeight > 1365)) {
314
+ // use2d = false;
315
+ // }
316
+ let canvansWidth = this.imgWidth;
317
+ let canvansHeight = this.imgHeight;
318
+ let size = Math.max(canvansWidth, canvansHeight)
319
+ let scalc = 1;
320
+ if(size > 1365) {
321
+ scalc = 1365 / size;
322
+ }
323
+ this.canvansWidth = canvansWidth * scalc;
324
+ this.canvansHeight = canvansHeight * scalc;
325
+ this.use2d = use2d;
326
+ this.initArea();
327
+ const src = val.src || this.imgSrc;
328
+ src && this.initImage(src, oldVal === undefined);
329
+ },
330
+ immediate: true
331
+ },
332
+ },
333
+ methods: {
334
+ /** 提供给wxs调用,用来接收图片变更数据 */
335
+ dataChange(e) {
336
+ // console.log('dataChange', e)
337
+ this.scaleWidth = e.width;
338
+ this.scaleHeight = e.height;
339
+ this.rotate = e.rotate;
340
+ this.offsetX = e.x;
341
+ this.offsetY = e.y;
342
+ },
343
+ /** 初始化裁剪区域布局信息 */
344
+ initArea() {
345
+ // 底部操作栏高度 = 底部底部操作栏内容高度 + 设备底部安全区域高度
346
+ this.sys.offsetBottom = uni.upx2px(100) + this.sys.safeAreaInsets.bottom;
347
+ // #ifndef H5
348
+ this.sys.windowTop = 0;
349
+ this.sys.navigation = true;
350
+ // #endif
351
+ // #ifdef H5
352
+ // h5平台的窗口高度是包含标题栏的
353
+ this.sys.windowTop = this.sys.windowTop || 44;
354
+ this.sys.navigation = this.navigation;
355
+ // #endif
356
+ let wp = this.widthPercent;
357
+ let hp = this.heightPercent;
358
+ if (this.imgWidth > this.imgHeight) {
359
+ hp = hp * this.imgHeight / this.imgWidth;
360
+ } else if (this.imgWidth < this.imgHeight) {
361
+ wp = wp * this.imgWidth / this.imgHeight;
362
+ }
363
+ const size = this.sys.windowWidth > this.sys.windowHeight ? this.sys.windowHeight : this.sys.windowWidth;
364
+ const width = size * wp / 100;
365
+ const height = size * hp / 100;
366
+ const left = (this.sys.windowWidth - width) / 2;
367
+ const right = left + width;
368
+ const top = (this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - height) / 2;
369
+ const bottom = this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - top;
370
+ this.area = { width, height, left, right, top, bottom };
371
+ this.scaleWidth = width;
372
+ this.scaleHeight = height;
373
+ },
374
+ /** 从本地选取图片 */
375
+ chooseImage(options) {
376
+ // #ifdef MP-WEIXIN || MP-JD
377
+ if(uni.chooseMedia) {
378
+ uni.chooseMedia({
379
+ ...options,
380
+ count: 1,
381
+ mediaType: ['image'],
382
+ success: (res) => {
383
+ this.resetData();
384
+ this.initImage(res.tempFiles[0].tempFilePath);
385
+ }
386
+ });
387
+ return;
388
+ }
389
+ // #endif
390
+ uni.chooseImage({
391
+ ...options,
392
+ count: 1,
393
+ sizeType:['original'],
394
+ sourceType: ['album', 'camera'],
395
+ success: (res) => {
396
+ console.log('极乐世界法律手段家乐福手机打')
397
+ console.log(res,'吉林师范老实交代联发科')
398
+ this.$emit('show');
399
+ this.resetData();
400
+ this.initImage(res.tempFiles[0].path);
401
+ }
402
+ });
403
+ },
404
+ /** 重置数据 */
405
+ resetData() {
406
+ this.imgSrc = '';
407
+ this.rotate = 0;
408
+ this.offsetX = 0;
409
+ this.offsetY = 0;
410
+ this.initArea();
411
+ },
412
+ /**
413
+ * 初始化图片信息
414
+ * @param {String} url 图片链接
415
+ */
416
+ initImage(url, isFirst) {
417
+ uni.getImageInfo({
418
+ src: url,
419
+ success: async (res) => {
420
+ if (isFirst && this.src === url) await (new Promise((resolve) => setTimeout(resolve, 50)));
421
+ this.imgSrc = res.path;
422
+ let scale = res.width / res.height;
423
+ let areaScale = this.area.width / this.area.height;
424
+ if (scale > 1) { // 横向图片
425
+ if (scale >= areaScale) { // 图片宽不小于目标宽,则高固定,宽自适应
426
+ this.scaleWidth = (this.scaleHeight / res.height) * this.scaleWidth * (res.width / this.scaleWidth);
427
+ } else { // 否则宽固定、高自适应
428
+ this.scaleHeight = res.height * this.scaleWidth / res.width;
429
+ }
430
+ } else { // 纵向图片
431
+ if (scale <= areaScale) { // 图片高不小于目标高,宽固定,高自适应
432
+ this.scaleHeight = (this.scaleWidth / res.width) * this.scaleHeight / (this.scaleHeight / res.height);
433
+ } else { // 否则高固定,宽自适应
434
+ this.scaleWidth = res.width * this.scaleHeight / res.height;
435
+ }
436
+ }
437
+ // 记录原始宽高,为缩放比列做限制
438
+ this.oldWidth = +this.scaleWidth.toFixed(2);
439
+ this.oldHeight = +this.scaleHeight.toFixed(2);
440
+ },
441
+ fail: (err) => {
442
+ console.error(err)
443
+ }
444
+ });
445
+ },
446
+ /**
447
+ * 剪切图片圆角
448
+ * @param {Object} ctx canvas 的绘图上下文对象
449
+ * @param {Number} radius 圆角半径
450
+ * @param {Number} scale 生成图片的实际尺寸与截取区域比
451
+ * @param {Function} drawImage 执行剪切时所调用的绘图方法,入参为是否执行了剪切
452
+ */
453
+ drawClipImage(ctx, radius, scale, drawImage) {
454
+ if(radius > 0) {
455
+ ctx.save();
456
+ ctx.beginPath();
457
+ const w = this.canvansWidth;
458
+ const h = this.canvansHeight;
459
+ if(w === h && radius >= w / 2) { // 圆形
460
+ ctx.arc(w / 2, h / 2, w / 2, 0, 2 * Math.PI);
461
+ } else { // 圆角矩形
462
+ if(w !== h) { // 限制圆角半径不能超过短边的一半
463
+ radius = Math.min(w / 2, h / 2, radius);
464
+ // radius = Math.min(Math.max(w, h) / 2, radius);
465
+ }
466
+ ctx.moveTo(radius, 0);
467
+ ctx.arcTo(w, 0, w, h, radius);
468
+ ctx.arcTo(w, h, 0, h, radius);
469
+ ctx.arcTo(0, h, 0, 0, radius);
470
+ ctx.arcTo(0, 0, w, 0, radius);
471
+ ctx.closePath();
472
+ }
473
+ ctx.clip();
474
+ drawImage && drawImage(true);
475
+ ctx.restore();
476
+ } else {
477
+ drawImage && drawImage(false);
478
+ }
479
+ },
480
+ /**
481
+ * 旋转图片
482
+ * @param {Object} ctx canvas 的绘图上下文对象
483
+ * @param {Number} rotate 旋转角度
484
+ * @param {Number} scale 生成图片的实际尺寸与截取区域比
485
+ */
486
+ drawRotateImage(ctx, rotate, scale) {
487
+ if(rotate !== 0) {
488
+ // 1. 以图片中心点为旋转中心点
489
+ const x = this.scaleWidth * scale / 2;
490
+ const y = this.scaleHeight * scale / 2;
491
+ ctx.translate(x, y);
492
+ // 2. 旋转画布
493
+ ctx.rotate(rotate * Math.PI / 180);
494
+ // 3. 旋转完画布后恢复设置旋转中心时所做的偏移
495
+ ctx.translate(-x, -y);
496
+ }
497
+ },
498
+ drawImage(ctx, image, callback) {
499
+ // 生成图片的实际尺寸与截取区域比
500
+ const scale = this.canvansWidth / this.area.width;
501
+ if(this.backgroundColor) {
502
+ if(ctx.setFillStyle) ctx.setFillStyle(this.backgroundColor);
503
+ else ctx.fillStyle = this.backgroundColor;
504
+ ctx.fillRect(0, 0, this.canvansWidth, this.canvansHeight);
505
+ }
506
+ this.drawClipImage(ctx, this.radius, scale, () => {
507
+ this.drawRotateImage(ctx, this.rotate, scale);
508
+ const r = this.rotate / 90;
509
+ ctx.drawImage(
510
+ image,
511
+ [
512
+ (this.offsetX - this.area.left),
513
+ (this.offsetY - this.area.top),
514
+ -(this.offsetX - this.area.left),
515
+ -(this.offsetY - this.area.top)
516
+ ][r] * scale,
517
+ [
518
+ (this.offsetY - this.area.top),
519
+ -(this.offsetX - this.area.left),
520
+ -(this.offsetY - this.area.top),
521
+ (this.offsetX - this.area.left)
522
+ ][r] * scale,
523
+ this.scaleWidth * scale,
524
+ this.scaleHeight * scale
525
+ );
526
+ });
527
+ },
528
+ /**
529
+ * 绘图
530
+ * @param {Object} canvas
531
+ * @param {Object} ctx canvas 的绘图上下文对象
532
+ * @param {String} src 图片路径
533
+ * @param {Function} callback 开始绘制时回调
534
+ */
535
+ draw2DImage(canvas, ctx, src, callback) {
536
+ // console.log('draw2DImage', canvas, ctx, src, callback)
537
+ if(canvas) {
538
+ const image = canvas.createImage();
539
+ image.onload = () => {
540
+ this.drawImage(ctx, image);
541
+ // 如果觉得`生成时间过长`或`出现生成图片空白`可尝试调整延迟时间
542
+ callback && setTimeout(callback, this.delay);
543
+ };
544
+ image.onerror = (err) => {
545
+ console.error(err)
546
+ uni.hideLoading();
547
+ };
548
+ image.src = src;
549
+ } else {
550
+ this.drawImage(ctx, src);
551
+ setTimeout(() => {
552
+ ctx.draw(false, callback);
553
+ }, 200);
554
+ }
555
+ },
556
+ /**
557
+ * 画布转图片到本地缓存
558
+ * @param {Object} canvas
559
+ * @param {String} canvasId
560
+ */
561
+ canvasToTempFilePath(canvas, canvasId) {
562
+ // console.log('canvasToTempFilePath', canvas, canvasId)
563
+ uni.canvasToTempFilePath({
564
+ canvas,
565
+ canvasId,
566
+ x: 0,
567
+ y: 0,
568
+ width: this.canvansWidth,
569
+ height: this.canvansHeight,
570
+ destWidth: this.imgWidth, // 必要,保证生成图片宽度不受设备分辨率影响
571
+ destHeight: this.imgHeight, // 必要,保证生成图片高度不受设备分辨率影响
572
+ fileType: this.fileType, // 目标文件的类型,默认png
573
+ success: (res) => {
574
+ console.log(res);
575
+ // 生成的图片临时文件路径
576
+ this.handleImage(res.tempFilePath);
577
+ },
578
+ fail: (err) => {
579
+ uni.hideLoading();
580
+ uni.showToast({ title: '裁剪失败,生成图片异常!', icon: 'none' });
581
+ }
582
+ }, this);
583
+ },
584
+ /** 确认裁剪 */
585
+ cropClick() {
586
+ uni.showLoading({ title: '裁剪中...', mask: true });
587
+ if(!this.use2d) {
588
+ const ctx = uni.createCanvasContext('imgCanvas', this);
589
+ ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight);
590
+ this.draw2DImage(null, ctx, this.imgSrc, () => {
591
+ this.canvasToTempFilePath(null, 'imgCanvas');
592
+ });
593
+ return;
594
+ }
595
+ // #ifdef MP-WEIXIN
596
+ const query = uni.createSelectorQuery().in(this);
597
+ query.select('#imgCanvas')
598
+ .fields({ node: true, size: true })
599
+ .exec((res) => {
600
+ const canvas = res[0].node;
601
+
602
+ const dpr = uni.getSystemInfoSync().pixelRatio;
603
+ canvas.width = res[0].width * dpr;
604
+ canvas.height = res[0].height * dpr;
605
+ const ctx = canvas.getContext('2d');
606
+ ctx.scale(dpr, dpr);
607
+ ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight);
608
+
609
+ this.draw2DImage(canvas, ctx, this.imgSrc, () => {
610
+ this.canvasToTempFilePath(canvas);
611
+ });
612
+ });
613
+ // #endif
614
+ },
615
+ handleImage(tempFilePath){
616
+ // 在H5平台下,tempFilePath 为 base64
617
+ // console.log(tempFilePath)
618
+ uni.hideLoading();
619
+ this.$emit('crop', { tempFilePath,path:this.imgSrc });
620
+ }
621
+ }
622
+ }
623
+ </script>
624
+
625
+ <style lang="scss" scoped>
626
+ .image-cropper {
627
+ position: fixed;
628
+ left: 0;
629
+ right: 0;
630
+ top: 0;
631
+ bottom: 0;
632
+ overflow: hidden;
633
+ display: flex;
634
+ flex-direction: column;
635
+ background-color: #000;
636
+ .img-canvas {
637
+ position: absolute !important;
638
+ transform: translateX(-100%);
639
+ }
640
+ .pic-preview {
641
+ width: 100%;
642
+ flex: 1;
643
+ position: relative;
644
+
645
+ .crop-mask-block {
646
+ background-color: rgba(51, 51, 51, 0.8);
647
+ z-index: 2;
648
+ position: fixed;
649
+ box-sizing: border-box;
650
+ pointer-events: none;
651
+ }
652
+ .crop-circle-box {
653
+ position: fixed;
654
+ box-sizing: border-box;
655
+ z-index: 2;
656
+ pointer-events: none;
657
+ overflow: hidden;
658
+ .crop-circle {
659
+ width: 100%;
660
+ height: 100%;
661
+ }
662
+ }
663
+ .crop-image {
664
+ padding: 0 !important;
665
+ margin: 0 !important;
666
+ border-radius: 0 !important;
667
+ display: block !important;
668
+ backface-visibility: hidden;
669
+ }
670
+ .crop-border {
671
+ position: fixed;
672
+ border: 1px solid #fff;
673
+ box-sizing: border-box;
674
+ z-index: 3;
675
+ pointer-events: none;
676
+ }
677
+ .crop-grid {
678
+ position: fixed;
679
+ z-index: 3;
680
+ border-style: dashed;
681
+ border-color: #fff;
682
+ pointer-events: none;
683
+ opacity: 0.5;
684
+ }
685
+ .crop-angle {
686
+ position: fixed;
687
+ z-index: 3;
688
+ border-style: solid;
689
+ border-color: #fff;
690
+ pointer-events: none;
691
+ }
692
+ }
693
+
694
+ .fixed-bottom {
695
+ position: fixed;
696
+ left: 0;
697
+ right: 0;
698
+ bottom: 0;
699
+ z-index: 99;
700
+ display: flex;
701
+ flex-direction: row;
702
+ background-color: $uni-bg-color-grey;
703
+
704
+ .action-bar {
705
+ position: absolute;
706
+ top: -90rpx;
707
+ left: 10rpx;
708
+ display: flex;
709
+ .rotate-icon {
710
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABCFJREFUaEPtml3IpVMUx3//ko/ChTIyiGFSMyhllI8bc4F85yuNC2FCqLmQC1+FZORiEkUMNW7UjKjJULgxV+NzSkxDhEkZgwsyigv119J63p7zvOc8z37OmXdOb51dz82711r7/99r7bXXXucVi3xokeNnRqCvB20fDmwAlgK/5bcD+FTSr33tHXQP2H4MeHQE0A+B5yRtLiUyDQJrgVc6AAaBpyV93kXkoBMIQLbfBS5NcK8BRwDXNcD+AdwnaVMbiWkRCPBBohpxHuK7M7865sclRdgNHVMhkF6IMIpwirFEUhzo8M7lwIvASTXEqyVtH8ZgagQSbOzsDknv18HZXpHn5IL8+94IOUm7miSmSqAttjPdbgGuTrnNktYsGgLpoYuAD2qg1zRTbG8P2D4SOC6/Q7vSHPALsE/S7wWy80RsPw/ckxMfSTq/LtRJwPbxwF3ASiCUTxwHCPAnEBfVF8AWSTtL7Ng+LfWOTfmlkn6udFsJ5K15R6a4kvX6yGyUFBvTOWzHXXFzCt4g6c1OArYj9iIGh43YgR+BvztXh1PSa4cMkd0jaVmXDduPAE+k3HpJD7cSGFKvfAc8FQUX8IOk/V2L1udtB/hTgdOBW4Aba/M7Ja1qs2f7euCNlHlZUlx4/495IWQ7Jl+qGbxX0gt9AHfJ2o6zFBVoNVrDKe+F3Sm8VdK1bQQ+A85JgXckXdkFaJx527cC9TpnVdvBtl3h2iapuhsGPdBw1b9xnUvaNw7AEh3bnwDnpuwGSfeP0rN9NvAMELXRXFkxEEK2nwQeSiOtRVQJwC4Z29cAW1Nuu6TVXTrN+SaBt4ErUug2Sa/2NdhH3vZy4NvU2S/p6D768w5xI3WOrAD7LtISFpGdIhVXKfaYvjd20wP13L9M0p4DBbaFRKToSLExVkr6qs+aIwlI6iwz+izUQqC+ab29PiMwqRcmPXczD8w8MFj1zg7xXEqbpdHCw7FgWSjafZL+KcQxtpjteCeflwYulFR/J3TabSslVkj6utPChAK2f6q9uZdLitKieLQRuExSvX9ZbLRUMFs09efpUZL+KtUfVo1GW/umNHC3pOhRLtiwfSbwZS6wV9IJfRdreuBBYH0a2STp9r4G+8jbXgc8mzoDT8VSO00ClwDv1ZR7XyylC4ec7ejaLUmdsV6Aw7oSbwFXpdFdks7qA6pU1na0aR6owgeIR/1cx63UzjAC0YXYVjMQHlkn6ZtSo21ytuPZGKFagQ/xsXZ/3iGuFrYdjafXG0DiQMeBi47c9/GV3BO247UV38n5o0UAP6xmu7jFOGxjRr66On5NPBDOCBsDTapxjHY1dyOcolNXnYlx1himE53p2PmNkxosevfavhg4Izt2k7TXPwZ2S6p6QZPin/2rwcQ7OKmBohCadJGF1P8PG6aaQBKVX/8AAAAASUVORK5CYII=');
711
+ background-size: 60% 60%;
712
+ background-repeat: no-repeat;
713
+ background-position: center;
714
+ width: 80rpx;
715
+ height: 80rpx;
716
+ &.is-reverse {
717
+ transform: rotateY(180deg);
718
+ }
719
+ }
720
+ }
721
+
722
+ .rechoose {
723
+ color: $uni-color-primary;
724
+ padding: 0 $uni-spacing-row-lg;
725
+ line-height: 100rpx;
726
+ }
727
+
728
+ .choose-btn {
729
+ color: $uni-color-primary;
730
+ text-align: center;
731
+ line-height: 100rpx;
732
+ flex: 1;
733
+ }
734
+
735
+ .button {
736
+ margin: auto $uni-spacing-row-lg auto auto;
737
+ background-color: $uni-color-primary;
738
+ color: #fff;
739
+ }
740
+ }
741
+
742
+ .safe-area-inset-bottom {
743
+ padding-bottom: 0;
744
+ padding-bottom: constant(safe-area-inset-bottom); // 兼容 IOS<11.2
745
+ padding-bottom: env(safe-area-inset-bottom); // 兼容 IOS>=11.2
746
+ }
747
+
748
+ }
749
+ </style>