|
|
@@ -4,21 +4,21 @@
|
|
|
<el-form-item label="广告位置" prop="advType">
|
|
|
<el-select v-model="queryParams.advType" placeholder="请选择广告位置" clearable size="small">
|
|
|
<el-option
|
|
|
- v-for="item in advTypeOptions"
|
|
|
- :key="item.dictValue"
|
|
|
- :label="item.dictLabel"
|
|
|
- :value="item.dictValue"
|
|
|
- />
|
|
|
+ v-for="item in advTypeOptions"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="item.dictValue"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="显示类型" prop="showType">
|
|
|
<el-select v-model="queryParams.showType" placeholder="请选择显示类型" clearable size="small">
|
|
|
- <el-option
|
|
|
- v-for="item in showTypeOptions"
|
|
|
- :key="item.dictValue"
|
|
|
- :label="item.dictLabel"
|
|
|
- :value="item.dictValue"
|
|
|
- />
|
|
|
+ <el-option
|
|
|
+ v-for="item in showTypeOptions"
|
|
|
+ :key="item.dictValue"
|
|
|
+ :label="item.dictLabel"
|
|
|
+ :value="item.dictValue"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
|
@@ -83,17 +83,17 @@
|
|
|
<el-table-column label="排序" align="center" prop="sort" />
|
|
|
<el-table-column label="广告位置" align="center" prop="advType">
|
|
|
<template slot-scope="scope">
|
|
|
- <el-tag prop="advType" v-for="(item, index) in advTypeOptions" v-if="scope.row.advType==item.dictValue">{{item.dictLabel}}</el-tag>
|
|
|
- </template>
|
|
|
+ <el-tag prop="advType" v-for="(item, index) in advTypeOptions" v-if="scope.row.advType==item.dictValue">{{item.dictLabel}}</el-tag>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="显示方式" align="center" prop="showType">
|
|
|
<template slot-scope="scope">
|
|
|
- <el-tag prop="showType" v-for="(item, index) in showTypeOptions" v-if="scope.row.showType==item.dictValue">{{item.dictLabel}}</el-tag>
|
|
|
- </template>
|
|
|
+ <el-tag prop="showType" v-for="(item, index) in showTypeOptions" v-if="scope.row.showType==item.dictValue">{{item.dictLabel}}</el-tag>
|
|
|
+ </template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="状态" align="center" prop="status">
|
|
|
<template slot-scope="scope">
|
|
|
- <el-tag prop="status" v-for="(item, index) in statusOptions" v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
|
|
|
+ <el-tag prop="status" v-for="(item, index) in statusOptions" v-if="scope.row.status==item.dictValue">{{item.dictLabel}}</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
|
|
@@ -136,17 +136,25 @@
|
|
|
<el-radio :label="2">视频</el-radio>
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="广告图片" prop="imageUrl" v-if="form.urlType==1">
|
|
|
- <el-upload
|
|
|
- v-model="form.icon"
|
|
|
- class="avatar-uploader"
|
|
|
- :action="uploadUrl"
|
|
|
- :show-file-list="false"
|
|
|
- :on-success="handleAvatarSuccess"
|
|
|
- :before-upload="beforeAvatarUpload">
|
|
|
- <img v-if="form.imageUrl" :src="form.imageUrl" class="avatar">
|
|
|
- <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
- </el-upload>
|
|
|
+ <el-form-item label="广告图片" prop="imageUrl" v-if="form.urlType==1">
|
|
|
+ <el-upload
|
|
|
+ v-model="form.icon"
|
|
|
+ class="avatar-uploader"
|
|
|
+ :action="uploadUrl"
|
|
|
+ :show-file-list="false"
|
|
|
+ :on-success="handleAvatarSuccess"
|
|
|
+ :before-upload="beforeAvatarUpload">
|
|
|
+ <img v-if="form.imageUrl" :src="form.imageUrl" class="avatar">
|
|
|
+ <i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
|
|
+ </el-upload>
|
|
|
+ <div class="image-size-tip">
|
|
|
+ <i class="el-icon-info"></i>
|
|
|
+ <span>建议尺寸:280×90px(比例28:9)</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="imageValidation.show" :class="['validation-message', imageValidation.type]">
|
|
|
+ <i :class="imageValidation.type === 'warning' ? 'el-icon-warning' : 'el-icon-success'"></i>
|
|
|
+ <span>{{ imageValidation.message }}</span>
|
|
|
+ </div>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="广告视频" prop="video" v-if="form.urlType==2">
|
|
|
<div>
|
|
|
@@ -190,7 +198,7 @@
|
|
|
</el-radio-group>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="排序" prop="sort">
|
|
|
- <el-input-number v-model="form.sort" :min="1" :max="99" ></el-input-number>
|
|
|
+ <el-input-number v-model="form.sort" :min="1" :max="99" ></el-input-number>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
@@ -211,6 +219,18 @@ export default {
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
+ // 广告图片验证相关
|
|
|
+ imageValidation: {
|
|
|
+ show: false,
|
|
|
+ type: 'success', // success 或 warning
|
|
|
+ message: ''
|
|
|
+ },
|
|
|
+ // 广告图片尺寸配置
|
|
|
+ imageSizeConfig: {
|
|
|
+ width: 280,
|
|
|
+ height: 90,
|
|
|
+ tolerance: 0.15 // 15%容差
|
|
|
+ },
|
|
|
uploadUrl:process.env.VUE_APP_BASE_API+"/common/uploadOSS",
|
|
|
baseUrl: process.env.VUE_APP_BASE_API,
|
|
|
videoAccept:"video/*",
|
|
|
@@ -313,21 +333,142 @@ export default {
|
|
|
this.form.content=text
|
|
|
},
|
|
|
handleAvatarSuccess(res, file) {
|
|
|
- if(res.code==200){
|
|
|
- this.form.imageUrl=res.url;
|
|
|
- }
|
|
|
- else{
|
|
|
- this.msgError(res.msg);
|
|
|
- }
|
|
|
+ if(res.code==200){
|
|
|
+ this.form.imageUrl=res.url;
|
|
|
+ // 验证广告图片尺寸
|
|
|
+ this.validateAdvertImage(res.url);
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ this.msgError(res.msg);
|
|
|
+ }
|
|
|
|
|
|
},
|
|
|
beforeAvatarUpload(file) {
|
|
|
const isLt1M = file.size / 1024 / 1024 < 200;
|
|
|
if (!isLt1M) {
|
|
|
this.$message.error('上传图片大小不能超过 200MB!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const isPic = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/jpg';
|
|
|
+ if (!isPic) {
|
|
|
+ this.$message.error('只能上传JPG、PNG、GIF格式的图片!');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 验证广告图片尺寸
|
|
|
+ validateAdvertImage(imageUrl) {
|
|
|
+ if (!imageUrl) {
|
|
|
+ this.imageValidation.show = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('开始验证广告图片尺寸:', imageUrl);
|
|
|
+
|
|
|
+ const img = new Image();
|
|
|
+ const config = this.imageSizeConfig;
|
|
|
+
|
|
|
+ // 设置超时处理
|
|
|
+ const timeoutId = setTimeout(() => {
|
|
|
+ this.imageValidation = {
|
|
|
+ show: true,
|
|
|
+ type: 'warning',
|
|
|
+ message: '图片加载超时,无法验证尺寸,请检查网络连接'
|
|
|
+ };
|
|
|
+ console.log('图片加载超时');
|
|
|
+ }, 10000);
|
|
|
+
|
|
|
+ img.onload = () => {
|
|
|
+ clearTimeout(timeoutId);
|
|
|
+ const { width: actualWidth, height: actualHeight } = img;
|
|
|
+ const { width: expectedWidth, height: expectedHeight, tolerance } = config;
|
|
|
+
|
|
|
+ console.log(`实际尺寸: ${actualWidth}x${actualHeight}px, 期望尺寸: ${expectedWidth}x${expectedHeight}px`);
|
|
|
+
|
|
|
+ // 计算比例差异
|
|
|
+ const expectedRatio = expectedWidth / expectedHeight;
|
|
|
+ const actualRatio = actualWidth / actualHeight;
|
|
|
+ const ratioDiff = Math.abs(actualRatio - expectedRatio) / expectedRatio;
|
|
|
+
|
|
|
+ console.log(`期望比例: ${expectedRatio.toFixed(3)}, 实际比例: ${actualRatio.toFixed(3)}, 差异: ${(ratioDiff * 100).toFixed(2)}%`);
|
|
|
+
|
|
|
+ this.imageValidation.show = true;
|
|
|
+
|
|
|
+ if (ratioDiff <= tolerance) {
|
|
|
+ this.imageValidation.type = 'success';
|
|
|
+ this.imageValidation.message = `✓ 尺寸符合要求 (实际: ${actualWidth}x${actualHeight}px)`;
|
|
|
+ console.log('尺寸验证通过');
|
|
|
+ } else {
|
|
|
+ this.imageValidation.type = 'warning';
|
|
|
+ this.imageValidation.message = `⚠ 尺寸不符合要求!实际: ${actualWidth}x${actualHeight}px,建议: ${expectedWidth}x${expectedHeight}px (比例${expectedRatio.toFixed(1)}:1)`;
|
|
|
+ console.log('尺寸验证失败');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ img.onerror = (error) => {
|
|
|
+ clearTimeout(timeoutId);
|
|
|
+ console.error('图片加载失败:', error);
|
|
|
+
|
|
|
+ // 检查URL格式和可访问性
|
|
|
+ this.checkImageUrl(imageUrl).then(isValid => {
|
|
|
+ if (!isValid) {
|
|
|
+ this.imageValidation = {
|
|
|
+ show: true,
|
|
|
+ type: 'warning',
|
|
|
+ message: '图片URL无效或无法访问,请检查图片地址是否正确'
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ this.imageValidation = {
|
|
|
+ show: true,
|
|
|
+ type: 'warning',
|
|
|
+ message: '图片加载失败,可能是跨域问题或格式不支持,请重新上传'
|
|
|
+ };
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理完整的图片URL
|
|
|
+ const fullImageUrl = this.getFullImageUrl(imageUrl);
|
|
|
+ img.crossOrigin = 'anonymous'; // 尝试处理跨域
|
|
|
+ img.src = fullImageUrl;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取完整的图片URL
|
|
|
+ getFullImageUrl(imageUrl) {
|
|
|
+ if (!imageUrl) return '';
|
|
|
+
|
|
|
+ // 如果已经是完整URL(http/https开头)
|
|
|
+ if (imageUrl.startsWith('http://') || imageUrl.startsWith('https://')) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是base64
|
|
|
+ if (imageUrl.startsWith('data:image/')) {
|
|
|
+ return imageUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是相对路径,拼接基础URL
|
|
|
+ const baseUrl = process.env.VUE_APP_BASE_API || '';
|
|
|
+ if (imageUrl.startsWith('/')) {
|
|
|
+ return baseUrl + imageUrl;
|
|
|
+ } else {
|
|
|
+ return baseUrl + '/' + imageUrl;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 检查图片URL有效性
|
|
|
+ async checkImageUrl(imageUrl) {
|
|
|
+ try {
|
|
|
+ const fullUrl = this.getFullImageUrl(imageUrl);
|
|
|
+ const response = await fetch(fullUrl, { method: 'HEAD' });
|
|
|
+ return response.ok;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('URL检查失败:', error);
|
|
|
+ return false;
|
|
|
}
|
|
|
- return isLt1M;
|
|
|
},
|
|
|
+
|
|
|
/** 查询广告列表 */
|
|
|
getList() {
|
|
|
this.loading = true;
|
|
|
@@ -358,6 +499,8 @@ export default {
|
|
|
advType: null,
|
|
|
showType: null
|
|
|
};
|
|
|
+ // 重置广告图片验证状态
|
|
|
+ this.imageValidation = { show: false, type: 'success', message: '' };
|
|
|
this.resetForm("form");
|
|
|
},
|
|
|
/** 搜索按钮操作 */
|
|
|
@@ -392,16 +535,24 @@ export default {
|
|
|
this.form.status = response.data.status.toString();
|
|
|
this.form.advType = response.data.advType.toString();
|
|
|
this.form.showType = response.data.showType ? response.data.showType.toString() : "";
|
|
|
+
|
|
|
+ // 如果有广告图片且是图片类型,验证其尺寸
|
|
|
+ if (this.form.imageUrl && this.form.urlType === 1) {
|
|
|
+ setTimeout(() => {
|
|
|
+ this.validateAdvertImage(this.form.imageUrl);
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
this.open = true;
|
|
|
this.title = "修改广告";
|
|
|
setTimeout(() => {
|
|
|
if(this.form.showType=="3"){
|
|
|
console.log(that.form.content)
|
|
|
if(this.form.content==null){
|
|
|
- that.$refs.myeditor.setText("");
|
|
|
+ that.$refs.myeditor.setText("");
|
|
|
}
|
|
|
else{
|
|
|
- that.$refs.myeditor.setText(that.form.content);
|
|
|
+ that.$refs.myeditor.setText(that.form.content);
|
|
|
}
|
|
|
}
|
|
|
}, 200);
|
|
|
@@ -431,62 +582,119 @@ export default {
|
|
|
handleDelete(row) {
|
|
|
const advIds = row.advId || this.ids;
|
|
|
this.$confirm('是否确认删除广告编号为"' + advIds + '"的数据项?', "警告", {
|
|
|
- confirmButtonText: "确定",
|
|
|
- cancelButtonText: "取消",
|
|
|
- type: "warning"
|
|
|
- }).then(function() {
|
|
|
- return delAdv(advIds);
|
|
|
- }).then(() => {
|
|
|
- this.getList();
|
|
|
- this.msgSuccess("删除成功");
|
|
|
- }).catch(() => {});
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(function() {
|
|
|
+ return delAdv(advIds);
|
|
|
+ }).then(() => {
|
|
|
+ this.getList();
|
|
|
+ this.msgSuccess("删除成功");
|
|
|
+ }).catch(() => {});
|
|
|
},
|
|
|
/** 导出按钮操作 */
|
|
|
handleExport() {
|
|
|
const queryParams = this.queryParams;
|
|
|
this.$confirm('是否确认导出所有广告数据项?', "警告", {
|
|
|
- confirmButtonText: "确定",
|
|
|
- cancelButtonText: "取消",
|
|
|
- type: "warning"
|
|
|
- }).then(() => {
|
|
|
- this.exportLoading = true;
|
|
|
- return exportAdv(queryParams);
|
|
|
- }).then(response => {
|
|
|
- this.download(response.msg);
|
|
|
- this.exportLoading = false;
|
|
|
- }).catch(() => {});
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ }).then(() => {
|
|
|
+ this.exportLoading = true;
|
|
|
+ return exportAdv(queryParams);
|
|
|
+ }).then(response => {
|
|
|
+ this.download(response.msg);
|
|
|
+ this.exportLoading = false;
|
|
|
+ }).catch(() => {});
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
-<style >
|
|
|
- .avatar-uploader .el-upload {
|
|
|
- border: 1px dashed #d9d9d9;
|
|
|
- border-radius: 6px;
|
|
|
- cursor: pointer;
|
|
|
- position: relative;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
- .avatar-uploader .el-upload:hover {
|
|
|
- border-color: #409EFF;
|
|
|
- }
|
|
|
-</style>
|
|
|
<style scoped>
|
|
|
+.image-size-tip {
|
|
|
+ margin-top: 5px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: #909399;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.image-size-tip i {
|
|
|
+ margin-right: 5px;
|
|
|
+ color: #409EFF;
|
|
|
+}
|
|
|
|
|
|
- .avatar-uploader-icon {
|
|
|
- font-size: 28px;
|
|
|
- color: #8c939d;
|
|
|
- width: 300px;
|
|
|
- height: 150px;
|
|
|
- line-height: 150px;
|
|
|
- text-align: center;
|
|
|
+.validation-message {
|
|
|
+ margin-top: 8px;
|
|
|
+ padding: 6px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ animation: fadeIn 0.3s ease-in;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message i {
|
|
|
+ margin-right: 6px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.success {
|
|
|
+ background-color: #f0f9ff;
|
|
|
+ border: 1px solid #b3d8ff;
|
|
|
+ color: #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.success i {
|
|
|
+ color: #67C23A;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.warning {
|
|
|
+ background-color: #fdf6ec;
|
|
|
+ border: 1px solid #f5dab1;
|
|
|
+ color: #E6A23C;
|
|
|
+}
|
|
|
+
|
|
|
+.validation-message.warning i {
|
|
|
+ color: #E6A23C;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes fadeIn {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(-5px);
|
|
|
}
|
|
|
- .avatar {
|
|
|
- width: 300px;
|
|
|
- height: 150px;
|
|
|
- display: block;
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
+.avatar-uploader-icon {
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+ width: 300px;
|
|
|
+ height: 150px;
|
|
|
+ line-height: 150px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
|
|
|
+.avatar {
|
|
|
+ width: 300px;
|
|
|
+ height: 150px;
|
|
|
+ display: block;
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style >
|
|
|
+.avatar-uploader .el-upload {
|
|
|
+ border: 1px dashed #d9d9d9;
|
|
|
+ border-radius: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.avatar-uploader .el-upload:hover {
|
|
|
+ border-color: #409EFF;
|
|
|
+}
|
|
|
</style>
|
|
|
|