上传器oss图片上传以及生成二维码海报
November 08, 2023
11037
一、图片上传至oss
图片上传至oss,接口成功但不会有返回信息,因此要在全局axios请求的响应拦截器做弹出提示框的限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 添加响应拦截器
service.interceptors.response.use(
(response: any) => {
const res = response.data;
// 统一错误处理
if (res.code === StatusCode.ERROR && res.msg == '用户未登录!') {
// ElMessage.error(res.msg);
storage.removeToken();
router.push({ path: '/login' });
closeLoading();
return Promise.reject(res);
}
if (res.code != StatusCode.SUCCESS || res.code == StatusCode.ERROR) {
closeLoading();
// 处理oss上传图片后成功但不返参问题
if (response.config.url.indexOf("aliyuncs.com") != -1) return;
ElMessage.error(res.msg);
return Promise.reject(res);
}
closeLoading();
return res;
},
(error: any) => {
ElMessage('系统繁忙 请刷新重新!');
closeLoading();
return Promise.reject(error);
}
);
二、qrcode.vue + html2canvas 生成二维码海报
qrcode.vue的两种使用方式:
组件方式使用:https://github.com/scopewu/qrcode.vue/blob/main/README-zh_cn.md
canvas操作方式: https://www.jianshu.com/p/d99e1f6c6a85
html2canvas使用: 它的原理就是先生成了二维码,再通过布局方式,使二维码图片放置在背景图的合适位置,然后截屏生成图片,需要注意的是其通过canvas.toDataURL生成的是base64格式的图片文件,如果需要上传oss,那么需要先转换成文件流
三、具体代码
代码如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264<template>
<el-dialog :close-on-click-modal="false" v-model="isDialog" title="速销海报" @close="clickClose">
<div class="content">
<!-- *产品图片: -->
<el-upload action :http-request="picUpload" :before-upload="uploadBefore" :file-list="imgList" list-type="picture-card" :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :limit="9">
<el-icon>
<plus />
</el-icon>
</el-upload>
</div>
<!-- 图片预览 -->
<el-dialog v-model="dialogVisible">
<img style="width: 100%; heigth: 100%" :src="dialogImageUrl" alt="" />
</el-dialog>
<template #footer>
<span class="dialog-footer">
<el-button @click="clickClose">取消</el-button>
<el-button type="primary" @click="confirmSubmit">确认</el-button>
</span>
</template>
</el-dialog>
<div class="invitePosterPage">
<!-- 这里是你生成完成的海报,背景图+二维码 -->
<div id="poster" class="flex-row" style="position: relative">
<img class="poster-bg" src="@/assets/avatar.jpg" />
<!-- canvas里是你的二维码 -->
<canvas class="qr" id="qrCode-canvas"></canvas>
</div>
</div>
</template>
<script>
import { reactive, toRefs, onMounted, defineComponent } from 'vue'
import { Plus } from '@element-plus/icons'
import { uploadImage, imgSign, speed, waitSpeed, deleteSpeedImg } from '@/api/ButtJoint'
import myUtils from '@/utils/myUtils'
import { ElMessage, ElMessageBox } from "element-plus";
import QRCode from 'qrcode'
import html2canvas from 'html2canvas';
export default defineComponent({
name: '',
components: {
Plus
},
props: {
productId: String,
closeDialog: {
type: Function,
default: () => {
console.log(`hah`);
}
}
},
setup(props) {
const state = reactive({
isDialog: true,
// 上传图片列表数组
imgList: [],
// 上传图片的预览
dialogImageUrl: '',
dialogVisible: false,
posterDataUrl: '',
})
// 关闭弹窗
const clickClose = () => {
props.closeDialog();
};
// 获取速销海报内容
const getWaitSpeed = async () => {
const res = await waitSpeed({ productId: props.productId });
res.data.urls.forEach((itm) => {
state.imgList.push({ url: itm })
})
};
// 移除图片
const handleRemove = async (file) => {
// 删除图片
await deleteSpeedImg({
productId: props.productId,
url: file.url
});
state.imgList = (state.imgList).filter((item) => item.url != file.url);
}
// 预览图片
const handlePictureCardPreview = (file) => {
state.dialogImageUrl = file.url
state.dialogVisible = true;
}
// 上传图片之前
const uploadBefore = (file) => {
//上传文件之前校验图片格式和大小
const isJPG = file.type === "image/jpeg" || file.type === "image/png" || file.type === "image/gif" || file.type === "image/jpg" || file.type === "image/x-icon" || file.type === "image/bmp";
const isLt20M = file.size / 1024 / 1024 < 20;
if (!isJPG) {
ElMessageBox.confirm("上传图片只能是 JPG、JPEG、PNG、GIF、ICO、BMP 格式!", "提示", {
confirmButtonText: "确认",
type: "info",
})
return false
}
if (!isLt20M) {
ElMessageBox.confirm("上传图片大小不能超过20MB!", "提示", {
confirmButtonText: "确认",
type: "info",
})
return false
}
};
// 图片上传至oss
const picUpload = async (file) => {
// 获取oss上传签名
const { data: signData } = await imgSign();
const ossData = new FormData();
// 通过工具类函数生成随机10位的图片名,避免图片名重复
const filename = myUtils.randomName(file.file.name, 10);
//图片名称
const keyValue = signData.dir + filename;
//文件名
ossData.append("name", file.file.name);
ossData.append("key", keyValue);
ossData.append("policy", signData.policy);
ossData.append("OSSAccessKeyId", signData.accessid);
ossData.append("success_action_status", '200');
ossData.append("signature", signData.signature);
ossData.append("file", file.file);
console.log(signData.host, "signData.host")
uploadImage(signData.host, ossData).then(() => {
const Url = signData.host + '/' + keyValue;
const imageUrl = {
url: Url
}
state.imgList.push(imageUrl);
});
};
// 确认提交
const confirmSubmit = async () => {
if (state.imgList.length < 6) {
return ElMessage.info('最少添加6张图片!');
}
const newList = [];
state.imgList.forEach((itm) => {
newList.push(itm.url)
});
const res = await speed({
productId: props.productId,
imagesUrl: newList
})
if (res.code == 200) {
ElMessage.success('添加成功!');
clickClose();
}
};
const base64toFile = (dataurl, filename = 'wowangmouren') => {
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let suffix = mime.split('/')[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], `${filename}.${suffix}`, {
type: mime
})
}
// base64图片上传至oss
const base64Upload = async (file) => {
// 获取oss上传签名
const { data: signData } = await imgSign();
const ossData = new FormData();
const filename = myUtils.randomName(file.name, 10);
//图片名称
const keyValue = signData.dir + filename;
//文件名
ossData.append("name", file.name);
ossData.append("key", keyValue);
ossData.append("policy", signData.policy);
ossData.append("OSSAccessKeyId", signData.accessid);
ossData.append("success_action_status", '200');
ossData.append("signature", signData.signature);
ossData.append("file", file);
uploadImage(signData.host, ossData).then(() => {
const Url = signData.host + '/' + keyValue;
console.log(Url, 'base64的图片')
const imageUrl = {
url: Url
}
state.imgList.push(imageUrl);
});
};
// 进入页面创建二维码并结合背景图生成海报
const createQRCode = () => {
//先用 QRCode 生成二维码 canvas,然后用 html2canvas 合成整张海报并转成 base64 显示出来
const canvas = document.getElementById('qrCode-canvas')
QRCode.toCanvas(canvas, 'www.baidu.com', (error) => {
if (error) {
console.log(error)
} else {
//qrcode 生成的二维码会带有一些默认样式,需要调整下
canvas.style.width = '10rem'
canvas.style.height = '10rem'
const poster = document.getElementById('poster')
html2canvas(poster).then(canvas => {
state.posterDataUrl = canvas.toDataURL('image/jpeg')
// base64格式的图片转换成文件流
const base64File = base64toFile(state.posterDataUrl);
if (base64File) {
base64Upload(base64File)
}
});
}
})
}
onMounted(() => {
getWaitSpeed();
// createQRCode();
console.log(props, '3.-组件挂载到页面之后执行-------onMounted')
})
return {
clickClose,
uploadBefore,
picUpload,
handleRemove,
handlePictureCardPreview,
confirmSubmit,
...toRefs(state),
}
},
})
</script>
<style scoped lang='scss'>
.content {
height: 35vh;
overflow-y: scroll;
text-align: left;
}
.invitePosterPage {
// width: 10px;
// height: 10px;
// display: none;
// .poster-bg {
// position: relative;
// }
.qr {
height: 1rem;
position: absolute;
bottom: 0.5rem;
left: 1.4rem;
}
}
</style>
- 本文作者:wowangmouren
- 本文链接:https://wangwewntao.top/2023/11/08/wmr_14/index.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!