4 changed files with 324 additions and 84 deletions
-
4.env.development
-
122src/views/weChatMiniProgram/baseSetting.vue
-
4src/views/weChatMiniProgram/bookrecommend.vue
-
268src/views/weChatMiniProgram/module/wecharQrCode.vue
@ -0,0 +1,268 @@ |
|||||
|
<template> |
||||
|
<div class="config-item"> |
||||
|
<div class="config-item-main"> |
||||
|
<span class="data-title">二维码</span> |
||||
|
<div class="upload-item" style="margin-bottom: 20px;"> |
||||
|
<p>公众号二维码</p> |
||||
|
<div style="display: flex; justify-content: flex-start;"> |
||||
|
<div class="image-container"> |
||||
|
<!-- loading遮罩 --> |
||||
|
<div v-if="isLoadingImg" class="image-loading"> |
||||
|
<div class="spinner" /> |
||||
|
<span class="loading-text">加载中...</span> |
||||
|
</div> |
||||
|
<img |
||||
|
v-show="!isLoadingImg" |
||||
|
:key="imageKey" |
||||
|
style="display: block; height: 120px; margin-right: 15px; transition: opacity 0.3s ease-in-out;" |
||||
|
:src="currentQrCodeUrl" |
||||
|
:class="{ 'image-loaded': !isLoadingImg && currentQrCodeUrl }" |
||||
|
alt="公众号二维码" |
||||
|
@load="handleImageLoad" |
||||
|
@error="handleImageError" |
||||
|
> |
||||
|
<!-- 错误提示 --> |
||||
|
<div v-if="imageError && !isLoadingImg" class="image-error"> |
||||
|
<i class="iconfont icon-error" /> |
||||
|
<span>加载失败</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="upload-img-input"> |
||||
|
<input |
||||
|
ref="fileInput" |
||||
|
type="file" |
||||
|
accept="image/*" |
||||
|
style="display: none;" |
||||
|
@change="changeFile($event)" |
||||
|
> |
||||
|
<div |
||||
|
class="upload-libImg" |
||||
|
:class="{ 'is-disabled': uploadLoading }" |
||||
|
@click="handleClickUpload" |
||||
|
> |
||||
|
<i class="iconfont icon-shangchuan2" /> |
||||
|
<span>{{ uploadLoading ? '上传中...' : '点击上传' }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div v-if="!isMiniProgram" class="config-remarks">二维码用于“总览屏”、“媒体屏”,在任意分屏编辑均可生效!</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { FetchEditScreenSetting } from '@/api/digitalScreen/index' |
||||
|
import { mapGetters } from 'vuex' |
||||
|
import { upload } from '@/utils/upload' |
||||
|
|
||||
|
export default { |
||||
|
name: 'WeChatQrCode', |
||||
|
props: { |
||||
|
qrCodeUrl: { |
||||
|
type: String, |
||||
|
default: null |
||||
|
}, |
||||
|
isMiniProgram: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
}, |
||||
|
recordId: { // 新增 prop |
||||
|
type: [Number, String], |
||||
|
default: null |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
defaultImg: require('@/assets/images/cover-bg.png'), |
||||
|
imageKey: 0, |
||||
|
localQrCodeUrl: null, |
||||
|
isLoadingImg: false, |
||||
|
imageError: false, |
||||
|
uploadLoading: false |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
...mapGetters(['baseApi', 'user']), |
||||
|
currentQrCodeUrl() { |
||||
|
if (this.localQrCodeUrl) { |
||||
|
return this.localQrCodeUrl |
||||
|
} |
||||
|
if (this.qrCodeUrl) { |
||||
|
// 父组件已经处理好完整url,子组件直接使用,不再拼接baseApi |
||||
|
return this.qrCodeUrl |
||||
|
} |
||||
|
return this.defaultImg |
||||
|
} |
||||
|
}, |
||||
|
watch: { |
||||
|
qrCodeUrl(newVal) { |
||||
|
this.localQrCodeUrl = newVal |
||||
|
this.reloadImage() |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.localQrCodeUrl = this.qrCodeUrl |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.$emit('ready') |
||||
|
}, |
||||
|
methods: { |
||||
|
handleClickUpload() { |
||||
|
if (this.uploadLoading) return |
||||
|
this.$refs.fileInput.click() |
||||
|
}, |
||||
|
|
||||
|
async changeFile(e) { |
||||
|
const file = e.target.files[0] |
||||
|
this.$refs.fileInput.value = '' |
||||
|
if (!file) return |
||||
|
|
||||
|
if (!file.type.startsWith('image/')) { |
||||
|
this.$message({ message: '只可上传图片', type: 'error', offset: 8 }) |
||||
|
return |
||||
|
} |
||||
|
// 文件大小校验 5MB |
||||
|
const MAX_SIZE = 5 * 1024 * 1024 |
||||
|
if (file.size > MAX_SIZE) { |
||||
|
this.$message.error('图片不能超过5MB') |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
this.uploadLoading = true |
||||
|
const res = await upload(this.baseApi + '/api/fileRelevant/uploadHttpsImg', file) |
||||
|
console.log('uploadHttpsImgres', res) |
||||
|
if (res.data.code === 200) { |
||||
|
const filePath = res.data.data |
||||
|
console.log('filePath', filePath) |
||||
|
await this.submitCover(filePath) |
||||
|
} else { |
||||
|
this.$message.error('图片上传失败') |
||||
|
} |
||||
|
} catch (err) { |
||||
|
console.error('上传异常:', err) |
||||
|
this.$message.error('图片上传失败') |
||||
|
} finally { |
||||
|
this.uploadLoading = false |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
async submitCover(imgUrl) { |
||||
|
const param = { |
||||
|
code: 'wechat_qr_code', |
||||
|
context: imgUrl, |
||||
|
remarks: null, |
||||
|
libcode: this.user.fonds.fondsNo, |
||||
|
id: this.recordId |
||||
|
} |
||||
|
console.log('param', param) |
||||
|
try { |
||||
|
await FetchEditScreenSetting(param) |
||||
|
this.$message.success('公众号二维码更新成功') |
||||
|
this.localQrCodeUrl = this.imgHttpsUrl + '/files/' + imgUrl |
||||
|
this.reloadImage() |
||||
|
this.$emit('update:qrCodeUrl', this.imgHttpsUrl + '/files/' + imgUrl) |
||||
|
this.$emit('triggerInit') |
||||
|
} catch (err) { |
||||
|
console.error('保存二维码失败', err) |
||||
|
this.$message.error('保存二维码失败') |
||||
|
throw err |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
reloadImage() { |
||||
|
this.isLoadingImg = true |
||||
|
this.imageError = false |
||||
|
this.imageKey++ |
||||
|
}, |
||||
|
handleImageLoad() { |
||||
|
this.isLoadingImg = false |
||||
|
this.imageError = false |
||||
|
}, |
||||
|
handleImageError() { |
||||
|
this.isLoadingImg = false |
||||
|
this.imageError = true |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
@import "~@/assets/styles/digitalScreen.scss"; |
||||
|
.image-container { |
||||
|
position: relative; |
||||
|
min-width: 120px; |
||||
|
height: 120px; |
||||
|
} |
||||
|
|
||||
|
.image-loading { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
height: 120px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
background-color: #f5f5f5; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
|
||||
|
.spinner { |
||||
|
width: 20px; |
||||
|
height: 20px; |
||||
|
border: 2px solid #eee; |
||||
|
border-top: 2px solid #0348f3; |
||||
|
border-radius: 50%; |
||||
|
animation: spin 1s linear infinite; |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
@keyframes spin { |
||||
|
0% { transform: rotate(0deg); } |
||||
|
100% { transform: rotate(360deg); } |
||||
|
} |
||||
|
|
||||
|
.loading-text { |
||||
|
font-size: 12px; |
||||
|
color: #666; |
||||
|
} |
||||
|
|
||||
|
.image-loaded { |
||||
|
opacity: 1; |
||||
|
} |
||||
|
|
||||
|
.image-error { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
height: 120px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
background-color: #f5f5f5; |
||||
|
border-radius: 4px; |
||||
|
color: #ED4A41; |
||||
|
font-size: 12px; |
||||
|
} |
||||
|
|
||||
|
.image-error .icon-error { |
||||
|
font-size: 20px; |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
.upload-libImg { |
||||
|
cursor: pointer; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 4px; |
||||
|
} |
||||
|
.upload-libImg.is-disabled { |
||||
|
cursor: not-allowed; |
||||
|
color: #999; |
||||
|
} |
||||
|
</style> |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue