添加上传图片组件

This commit is contained in:
熊丽君
2022-01-05 15:01:49 +08:00
parent 3797d82cd9
commit be53c4afc9
4 changed files with 625 additions and 40 deletions

View File

@ -0,0 +1,197 @@
<template>
<div class="component-upload-image">
<el-upload
:action="uploadImgUrl"
list-type="picture-card"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
name="file"
:on-remove="handleRemove"
:show-file-list="true"
:headers="headers"
:file-list="fileList"
:on-preview="handlePictureCardPreview"
:class="{ hide: fileList.length >= limit }"
>
<el-icon class="avatar-uploader-icon"><plus /></el-icon>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件
</div>
<el-dialog
v-model="dialogVisible"
title="预览"
width="800px"
append-to-body
>
<img
:src="dialogImageUrl"
style="display: block; max-width: 100%; margin: 0 auto"
/>
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
const props = defineProps({
modelValue: [String, Object, Array],
// 图片数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
});
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
watch(() => props.modelValue, val => {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(",");
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === "string") {
if (item.indexOf(baseUrl) === -1) {
item = { name: baseUrl + item, url: baseUrl + item };
} else {
item = { name: item, url: item };
}
}
return item;
});
} else {
fileList.value = [];
return [];
}
});
// 删除图片
function handleRemove(file, files) {
const findex = fileList.value.map(f => f.name).indexOf(file.name);
if (findex > -1) {
fileList.value.splice(findex, 1);
emit("update:modelValue", listToString(fileList.value));
}
}
// 上传成功回调
function handleUploadSuccess(res) {
fileList.value.push({ name: res.fileName, url: res.fileName });
emit("update:modelValue", listToString(fileList.value));
proxy.$modal.closeLoading();
}
// 上传前loading加载
function handleBeforeUpload(file) {
let isImg = false;
if (props.fileType.length) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = props.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
} else {
isImg = file.type.indexOf("image") > -1;
}
if (!isImg) {
proxy.$modal.msgError(
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
);
return false;
}
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
return false;
}
}
proxy.$modal.loading("上传中");
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}
// 上传失败
function handleUploadError() {
proxy.$modal.msgError("上传失败");
proxy.$modal.closeLoading();
}
// 预览
function handlePictureCardPreview(file) {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
}
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url.replace(baseUrl, "") + separator;
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {
display: none;
}
// 去掉动画效果
:deep(.el-list-enter-active),
:deep(.el-list-leave-active) {
transition: all 0s;
}
:deep(.el-list-enter, .el-list-leave-active) {
opacity: 0;
transform: translateY(0);
}
</style>

View File

@ -0,0 +1,188 @@
<template>
<div>
<el-dialog
v-model="dialogVisible"
width="516px"
:before-close="onClose"
title="活动申请"
center
:close-on-click-modal="false"
>
<el-dialog v-model="innerVisible" width="20%" title="" append-to-body>
<div>
<div class="_contact">请联系平台客服发布活动</div>
<div class="_img">
<img
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F01%2F39%2F53%2F71573cc4a35de96.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1643849770&t=80c12feeca42dad377bbdde1d6e78f33"
alt=""
/>
</div>
</div>
</el-dialog>
<el-form ref="formRef" :rules="rules" :model="form" label-width="95px">
<el-form-item label="活动名称:" prop="field">
<el-input
v-model="form.field"
maxlength="30"
show-word-limit
></el-input>
</el-form-item>
<el-form-item label="申请人:" prop="field2">
<el-input
v-model="form.field2"
maxlength="30"
show-word-limit
></el-input>
</el-form-item>
<el-form-item label="联系人:" prop="field3">
<el-input
v-model="form.field3"
maxlength="30"
show-word-limit
></el-input>
</el-form-item>
<el-form-item label="联系电话:" prop="field4">
<el-input
v-model="form.field4"
maxlength="11"
show-word-limit
></el-input>
</el-form-item>
<el-form-item label="活动地点:" prop="field5">
<el-input v-model="form.field5"></el-input>
</el-form-item>
<el-form-item label="人数上限:" prop="field6">
<el-input v-model="form.field6"></el-input>
</el-form-item>
<el-form-item label="报名费用:" prop="field7">
<el-input v-model="form.field7">
<template #append>元</template>
</el-input>
</el-form-item>
<el-form-item label="邀请对象:" prop="field8">
<el-checkbox-group v-model="form.field8">
<el-checkbox label="专家" />
<el-checkbox label="企业" />
<el-checkbox label="政府" />
<el-checkbox label="事业单位" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="活动介绍:" prop="field9">
<el-input v-model="form.field9" type="textarea"></el-input>
</el-form-item>
<el-form-item label="活动封面:" prop="">
<ImageUpload v-model:modelValue="form.field8" :isShowTip="false" />
</el-form-item>
<el-form-item>
<el-row :gutter="10">
<el-col :span="12">
<el-button
type="text"
style="
width: 100%;
border-radius: 0;
color: #333333;
font-size: 16px;
background-color: #e6e6e6;
"
@click="onClose"
>取消</el-button
>
</el-col>
<el-col :span="12">
<el-button style="width: 100%" class="x_btns" @click="onSubmit"
>确定</el-button
>
</el-col>
</el-row>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script setup>
const imageUrl = ref("");
const props = defineProps({
dialogVisible: {
required: true,
type: Boolean,
},
});
const innerVisible = ref(false);
const form = reactive({
field: "",
field2: "",
field3: "",
field4: "",
field5: "",
field6: "",
field7: "",
field8: [],
field9: "",
field10: "",
});
const { proxy } = getCurrentInstance();
const rules = ref({
field: [{ required: true, message: "活动名称不能为空", trigger: "blur" }],
field2: [{ required: true, message: "申请人不能为空", trigger: "blur" }],
field3: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
field4: [
{ required: true, message: "联系电话不能为空", trigger: "blur" },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",
trigger: "blur",
},
],
field5: [{ required: true, message: "活动地点不能为空", trigger: "blur" }],
field6: [{ required: true, message: "人数上限不能为空", trigger: "blur" }],
field7: [{ required: true, message: "报名费用不能为空", trigger: "blur" }],
field8: [
{
type: "array",
required: true,
message: "邀请对象不能为空",
trigger: "change",
},
],
field9: [{ required: true, message: "活动介绍不能为空", trigger: "blur" }],
field10: [{ required: true, message: "活动封面不能为空", trigger: "blur" }],
});
const emit = defineEmits();
function onClose() {
proxy.resetForm("formRef");
emit("update:dialogVisible", !props.dialogVisible);
}
/** 提交按钮 */
function onSubmit() {
innerVisible.value = true; // 需要删除
proxy.$refs.formRef.validate((valid) => {
if (valid) {
console.log(rules.value);
innerVisible.value = true;
}
});
}
</script>
<style lang="scss" scoped>
::v-deep(.el-input__inner) {
padding-right: 55px;
}
._contact {
text-align: center;
font-size: 20px;
font-weight: bold;
color: #333333;
}
._img {
margin: 0 auto;
margin-top: 12px;
width: 236px;
height: 236px;
padding: 15px;
img {
width: 100%;
height: 100%;
}
}
</style>

View File

@ -31,6 +31,8 @@ import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel } from
import Pagination from '@/components/Pagination'
// 自定义表格工具组件
import RightToolbar from '@/components/RightToolbar'
// 图片上传组件
import ImageUpload from "@/components/ImageUpload"
// 自定义树选择组件
import TreeSelect from '@/components/TreeSelect'
// 字典标签组件
@ -53,6 +55,7 @@ app.config.globalProperties.selectDictLabel = selectDictLabel
app.component('DictTag', DictTag)
app.component('Pagination', Pagination)
app.component('TreeSelect', TreeSelect)
app.component('ImageUpload', ImageUpload)
app.component('RightToolbar', RightToolbar)
app.use(router)

View File

@ -1,7 +1,12 @@
<template>
<div class="activity">
<div style="height: 394px; background-color: #ccc"></div>
<div class="box conter1000">
<webReleaseActive v-model:dialogVisible="dialogVisible"></webReleaseActive>
<div class="_banner" style="height: 394px; background-color: #ccc">
<div class="_publish conter1000">
<el-button @click="dialogVisible = true">发布活动</el-button>
</div>
</div>
<div class="box conter1000" v-show="!isShow">
<el-row :gutter="10">
<el-col :span="5">
<el-select
@ -24,29 +29,31 @@
</el-col>
</el-row>
<div v-loading="loading">
<div class="_item" v-for="(item, index) in 3" :key="index">
<div
class="_item pointer"
v-for="item in dataList"
:key="item.id"
@click="handleDetail(item)"
>
<div class="_l">
<el-image
style="width: 358px; height: 200px; vertical-align: middle"
src="https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg"
:src="item.src"
fit="fill"
></el-image>
</div>
<div class="_r">
<p class="text_hidden">
订单利润模型构建企业利润机器人智能感知与控制专场 |
合肥高新区科技成果供需对接活动
</p>
<div class="_time">
活动时间2021-10-14 13:30:00 ~ 2021-10-16 16:30:00
</div>
<p class="text_hidden">{{ item.title }}</p>
<div class="_time">活动时间{{ item.time }}</div>
<div class="_info">
<span class="fl"><span class="x_blue">16</span> 人报名</span>
<el-button class="fr x_btns" v-if="index == 0" disabled
<span class="fl"
><span class="x_blue">{{ item.user }}</span> 人报名</span
>
<el-button class="fr x_btns" v-if="item.status == 1" disabled
>已报名</el-button
>
<el-button
v-else-if="index == 1"
v-else-if="item.status == 2"
class="fr x16 x_blue x_border_blue"
style="border-radius: 0"
>报名</el-button
@ -71,12 +78,66 @@
@pagination="getList"
/>
</div>
<div class="box2 conter1000" v-show="isShow">
<webBreadcrumb
v-model:isShow="isShow"
v-model:breadcrumbTitle="breadcrumbTitle"
></webBreadcrumb>
<div class="_head">
<div class="_l">
<el-image
style="width: 358px; height: 100%; vertical-align: middle"
src="https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg"
fit="cover"
></el-image>
</div>
<div class="_r">
<p class="_title text_hidden">
订单利润模型构建企业利润机器人智能感知与控制专场 |
合肥高新区科技成果供需对接活动
</p>
<p class="_brief text_hidden">
活动简介订单利润模型构建企业利润机器人智能感知与控制专场 |
合肥高新企业利润机 区科技成果
供需对接活动订单利润模型构建企业利润机器人智能感知供需对接活动订单利润模型构建企业利润机器人智能感知
</p>
<p class="_classif">活动分类教育</p>
<p class="_time">
活动时间2021-10-14 13:30:00 ~ 2021-10-16 16:30:00
</p>
<p class="_place">
活动地点安徽省-合肥市-蜀山区 科学大道233号来福酒店1号会议厅
</p>
<p class="_user">
<el-button class="x_btns" disabled>已报名</el-button>
<span class="_num"><span class="x_blue">16</span> 人报名</span>
</p>
</div>
</div>
<div class="_info">
<div class="_l">
<p class="_tit">活动详情</p>
<div class="_txt">
本项目将生产废水分质处理后提升进入曝气微电解反应器内通过铁碳原料在酸性情况下形成微电池首先对铜氨络合物破络其次对油墨等有机物质开环断链提高废水的可生化性更突出的是利用金属离子的活性铁置换其他金属离子从而从废水中除去然后经生化系统处理后出水各污染物指标稳定达标排放本项目具有处理效率高以废治废能耗低管理简单出水稳定达标等优点
出水各污染物指标稳定达标排放本项目具有处理效率高以废治废能耗低管理简单出水稳定达标等优点
</div>
<div class="_txt">
本项目将生产废水分质处理后提升进入曝气微电解反应器内通过铁碳原料在酸性情况下形成微电池首先对铜氨络合物破络其次对油墨等有机物质开环断链提高废水的可生化性更突出的是利用金属离子的活性铁置换其他金属离子从而从废水中除去然后经生化系统处理后出水各污染物指标稳定达标排放本项目具有处理效率高以废治废能耗低管理简单出水稳定达标等优点
出水各污染物指标稳定达标排放本项目具有处理效率高以废治废能耗低管理简单出水稳定达标等优点
</div>
</div>
<div class="_r">联系我</div>
</div>
</div>
<webFooter></webFooter>
</div>
</template>
<script setup>
import webFooter from "@/components/webFooter/index.vue";
import webBreadcrumb from "@/components/webBreadcrumb/index.vue";
import webReleaseActive from "@/components/webReleaseActive/index.vue";
const dialogVisible = ref(false);
const loading = ref(true);
const total = ref(1);
const queryParams = reactive({
@ -86,18 +147,77 @@ const queryParams = reactive({
value2: "",
value3: "",
});
let dataList = ref([]);
const isShow = ref(false);
let breadcrumbTitle = reactive({
id: null,
title: "",
twoTitle: "",
});
/** 查询 */
function getList() {
loading.value = true;
setTimeout(() => {
dataList.value = [
{
id: 1,
title:
"订单利润模型——构建企业利润机器人智能感知与控制专场 | 合肥高新区科技成果供需对接活动",
src: "https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg",
time: "2021-10-14 13:30:00 ~ 2021-10-16 16:30:00",
user: 16,
status: 1,
},
{
id: 2,
title:
"订单利润模型——构建企业利润机器人智能感知与控制专场 | 合肥高新区科技成果供需对接活动",
src: "https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg",
time: "2021-10-14 13:30:00 ~ 2021-10-16 16:30:00",
user: 17,
status: 2,
},
{
id: 3,
title:
"订单利润模型——构建企业利润机器人智能感知与控制专场 | 合肥高新区科技成果供需对接活动",
src: "https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg",
time: "2021-10-14 13:30:00 ~ 2021-10-16 16:30:00",
user: 18,
status: 3,
},
];
loading.value = false;
}, 1000);
}, 500);
}
function handleDetail(item) {
breadcrumbTitle.id = item.id;
breadcrumbTitle.title = "活动报名";
breadcrumbTitle.twoTitle = "活动报名详情";
isShow.value = !isShow.value;
}
getList();
</script>
<style lang="scss" scoped>
.activity {
background-color: #f2f6ff;
._banner {
position: relative;
._publish {
position: relative;
.el-button {
position: absolute;
top: 171px;
right: 46px;
background-color: #ffc600;
color: #fff;
border: 0;
border-radius: 0;
font-size: 36px;
font-weight: bold;
}
}
}
.box {
position: relative;
padding-top: 20px;
@ -115,38 +235,115 @@ getList();
background-color: #0054ff;
}
}
}
._item {
display: flex;
margin-top: 16px;
._r {
flex: 1;
padding: 36px 20px 0 16px;
background-color: #fff;
p {
margin-top: 0;
font-size: 16px;
font-weight: 600;
color: #333333;
line-height: 30px;
}
._time {
margin-bottom: 7px;
font-size: 16px;
font-weight: 400;
color: #666666;
}
._info {
.fl {
._item {
display: flex;
margin-top: 16px;
._r {
flex: 1;
padding: 36px 20px 0 16px;
background-color: #fff;
p {
margin-top: 0;
font-size: 16px;
font-weight: 600;
color: #333333;
line-height: 30px;
}
._time {
margin-bottom: 7px;
font-size: 16px;
font-weight: 400;
color: #666666;
span {
font-size: 30px;
}
._info {
.fl {
font-size: 16px;
font-weight: 400;
color: #666666;
span {
font-size: 30px;
}
}
}
}
}
}
.box2 {
._head {
padding: 20px;
background-color: #fff;
display: flex;
._r {
padding-left: 18px;
p {
margin: 11px 0;
}
._title {
font-size: 18px;
font-weight: 500;
color: #333333;
line-height: 30px;
}
._brief,
._classif,
._time,
._place {
font-size: 14px;
font-weight: 400;
color: #666666;
}
._brief {
line-height: 24px;
}
._user {
margin-bottom: 0;
display: flex;
align-items: flex-end;
._num {
margin-left: 10px;
font-size: 16px;
font-weight: 400;
color: #666666;
.x_blue {
font-size: 30px;
}
}
}
}
}
._info {
display: flex;
margin-top: 16px;
margin-bottom: 35px;
._l {
width: 662px;
margin-right: 14px;
padding: 14px 40px 0 20px;
background-color: #fff;
._tit {
&::before {
content: "";
display: inline-block;
margin-right: 5px;
width: 5px;
height: 5px;
background-color: #0054ff;
vertical-align: middle;
}
}
._txt {
margin-bottom: 45px;
font-size: 14px;
font-weight: 400;
color: #666666;
line-height: 24px;
}
}
._r {
flex: 1;
background-color: #fff;
}
}
}
}
</style>