
<template>
<div>
<el-select
ref="provinceSelect"
v-model="chooseProvince"
@change="choseProvince"
class="province"
placeholder="省">
<el-option
v-for="item in province"
:key="item.id"
:label="item.value"
:value="item.id">
</el-option>
</el-select>
<el-select
ref="citySelect"
v-model="chooseCity"
@change="choseCity"
placeholder="市">
<el-option
v-for="item in cities"
:key="item.id"
:label="item.value"
:value="item.id">
</el-option>
</el-select>
</div>
</template>
<script>
import axios from 'axios'
import mapData from "@/assets/mapData/map.json"
export default {
props: {
selProvince: String,
selCity: String
},
data () {
return {
province:'',
cities: [],
counties: [],
city:'',
block:'',
acProvince:'',
acCity:'',
chooseProvince:this.selProvince,
chooseCity:this.selCity,
}
},
methods:{
// 加载china地点数据,三级
getCityData:function(){
var that = this
var data = mapData
that.province = []
that.city = []
that.block = []
// 省市区数据分类
for (var item in data) {
if (item.match(/0000$/)) {//省
that.province.push({id: item, value: data[item], children: []})
} else if (item.match(/00$/)) {//市
that.city.push({id: item, value: data[item], children: []})
} else {//区
that.block.push({id: item, value: data[item]})
}
}
// 分类市级
for (var index in that.province) {
for (var index1 in that.city) {
if (that.province[index].id.slice(0, 2) === that.city[index1].id.slice(0, 2)) {
that.province[index].children.push(that.city[index1])
}
}
}
},
// 选省
choseProvince:function(e) {
for (var index2 in this.province) {
if (e === this.province[index2].id) {
// console.log(this.province[index2].id)//你选择的省级编码
// console.log(this.province[index2].value)//省级编码 对应的汉字
this.acProvince=this.province[index2].value
this.cities = this.province[index2].children
// this.chooseCity = this.province[index2].children[0].value
this.chooseCity = ""
this.E = this.cities[0].id
}
}
},
// 选市
choseCity:function(e) {
for (var index3 in this.city) {
if (e === this.city[index3].id) {
this.acCity=this.city[index3].value
}
this.E=e;
}
}
},
created:function(){
this.getCityData()
},
watch: {
acProvince(val) {
this.$emit('changeName', this.acProvince)
this.acProvince = val
this.$refs.provinceSelect.visible = false
},
acCity(val) {
this.$emit('changeNames', this.acCity)
this.$refs.citySelect.visible = false
},
acCouty(val) {
this.$emit('changeRegion', this.acCouty)
},
selProvince: function(newValue) {
this.chooseProvince= newValue;
},
selCity: function(newValue) {
this.chooseCity= newValue;
},
},
}
</script>
<style lang="less" scoped>
.province{
// width: 200px;
margin-right: 20px;
}
</style>
页面使用:
<template>
<div class="demandBox">
<div class="titleBox">
<div class="leftTitle">{{ title }}</div>
</div>
<div class="line"></div>
<div class="form">
<el-form
:model="form"
:rules="rules"
ref="formRef"
style="max-width: 600px"
label-width="130px"
class="demo-ruleForm"
label-position="right"
>
<el-form-item label="需求名称:" prop="title" class="item">
<el-input
placeholder="请输入需求名称"
autocomplete="off"
v-model="form.title"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="需求来源:" class="item" prop="source">
<el-input
placeholder="请输入需求来源"
autocomplete="off"
v-model="form.source"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="合作方式:" prop="type">
<el-checkbox-group v-model="form.type">
<el-checkbox
:label="item.id"
v-for="item in cooperateway"
:key="item.id"
>{{ item.name }}</el-checkbox
>
</el-checkbox-group>
</el-form-item>
<el-form-item label="预投资金额(万):" prop="price" class="item">
<el-input
placeholder="面议"
autocomplete="off"
v-model="form.price"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="所在地:" class="location">
<cascader-two
v-if="title == '发布需求'"
@changeName="lockValue"
@changeNames="lock"
></cascader-two>
<cascader-two
v-if="title == '编辑需求' || title == '编辑草稿'"
:selProvince="form.province"
:selCity="form.city"
@changeName="lockValue"
@changeNames="lock"
></cascader-two>
</el-form-item>
<el-form-item label="解决时限要求:" class="item" prop="timelimit">
<el-input
placeholder="请输入解决时限要求"
autocomplete="off"
v-model="form.timelimit"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="学科分类:">
<el-checkbox-group v-model="form.xueke">
<el-checkbox
:label="item.id"
v-for="item in xueke"
:key="item.id"
>{{ item.name }}</el-checkbox
>
</el-checkbox-group>
</el-form-item>
<el-form-item label="难题描述:" class="item" prop="context">
<el-input
type="textarea"
v-model="form.context"
placeholder="请输入难题描述"
:rows="8"
></el-input>
</el-form-item>
<el-form-item label="需求材料:" class="item">
<div class="uploadBox">
<el-upload
class="upload-demo"
action="#"
multiple
:before-upload="uploadFile"
>
<el-button type="primary" class="upload">上传材料</el-button>
</el-upload>
<div class="uploadList">
<ul class="uploadTitle">
<li>文件名称</li>
<li>文件类型</li>
<li>操作</li>
</ul>
<ul v-for="(item, index) in files" :key="item.id" class="files">
<li :title="item.file_name">{{ item.file_name }}</li>
<li class="fileType">{{ item.file_type }}</li>
<li class="fileAction">
<span @click="delFile(item.id, index)">删除</span>
<span @click="showImg(item.file_url)" v-if="item.file_type=='图片'"> | 预览</span>
</li>
</ul>
</div>
</div>
</el-form-item>
<el-form-item label="联系人:" prop="liaison" class="item">
<el-input
placeholder="请输入联系人"
autocomplete="off"
v-model="form.liaison"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="联系电话:" prop="telephone" class="item">
<el-input
placeholder="请输入联系电话"
autocomplete="off"
v-model="form.telephone"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="联系邮箱:" prop="email" class="item">
<el-input
placeholder="请输入联系邮箱"
autocomplete="off"
v-model="form.email"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="邮政编码:" class="item" prop="post_code">
<el-input
placeholder="请输入邮政编码"
autocomplete="off"
v-model="form.post_code"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item label="通讯地址:" class="item" prop="address">
<el-input
placeholder="请输入通讯地址"
autocomplete="off"
v-model="form.address"
style="max-width: 400px"
></el-input>
</el-form-item>
<el-form-item class="item">
<el-button
type="primary"
class="subButton"
@click="setForm(formRef, form)"
>提交需求</el-button
>
<el-button
type="primary"
class="saveButton"
v-if="title == '发布需求' || title == '编辑草稿'"
@click="keepForm(formRef, form)"
>保存草稿</el-button
>
</el-form-item>
</el-form>
</div>
<div class="notice">
<span>!</span>
需求提交之后,平台会在5个工作日内进行审核,通过审核的需求才能展示在需求中心。
</div>
<el-dialog v-model="fileDialog" title="提示" width="30%">
<span>{{ msg }}</span>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="close()"> 确定 </el-button>
</span>
</template>
</el-dialog>
<el-dialog v-model="dialogImg">
<img
w-full
:src="defaultconfig.requestApi + dialogImageUrl"
alt="Preview Image"
style="width: 100%"
/>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { defineComponent, ref, reactive, watch, onMounted } from "vue";
import type { FormInstance } from "element-plus";
import "element-plus/es/components/message/style/css";
import { ElMessage, ElMessageBox } from "element-plus";
import { useRoute, useRouter } from "vue-router";
import {
addDemand,
getDemandDetailInfo,
updateDemand,
keepDemand,
} from "@/api/demandApi";
import { getdemandtypelist, getDemanddiclist } from "@/api/dictionaryApi";
import { getFiles, upload, delFiles, addFiles } from "@/api/uploadApi";
import { defaultconfig } from "@/utils/defaultconfig";
import cascaderTwo from "../../cascader/cascaderTwo.vue";
import { checkDatas } from "@/utils/defaultconfig";
name: "demand";
components: {
cascaderTwo;
}
const title = ref();
const curId = ref();
const files = ref([]);
const dialogImageUrl = ref("");
const dialogImg = ref(false);
const fileDialog = ref(false);
const msg = ref();
const codeList = ref([]); //合作方式
const cooperateway = ref([]); //合作方式
const xueke = ref([]);
const formRef = ref<FormInstance>();
const textarea = ref("");
const formLabelWidth = "500px";
const form = reactive({
title: "",
source: "",
type: [],
xueke: [],
price: "",
province: "",
city: "",
timelimit: "",
context: "",
liaison: "",
telephone: "",
email: "",
post_code: "",
address: "",
fileModels: [
{
file_type: 0,
file_name: "",
file_url: "",
},
],
});
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
};
const router = useRouter();
const rules = reactive({
title: [
{ required: true, message: "请输入需求名称" },
{ max: 50, message: "字符长度不能超过50" },
],
source: [{ max: 50, message: "字符长度不能超过50" }],
email: [
{ required: true, validator: checkDatas.checkEmail, trigger: "blur" },
],
telephone: [
{ required: true, validator: checkDatas.checkPhone, trigger: "blur" },
],
liaison: [
{ required: true, message: "请输入联系人" },
{ max: 20, message: "字符长度不能超过20" },
],
timelimit: [{ max: 50, message: "字符长度不能超过50" }],
context: [{ max: 500, message: "字符长度不能超过500" }],
post_code: [{ validator: checkDatas.checkCode, trigger: "blur" }],
address: [{ max: 100, message: "字符长度不能超过100" }],
price: [{ required: true, message: "请输入预投资金额" }],
});
const route = useRoute();
curId.value = route.query.id;
watch(
() => [route.query.title, files.value],
(newVal, oldVal) => {
//此时返回的是数组,按下标获取对应值
title.value = newVal[0] ? newVal[0] : "";
files.value = newVal[1];
},
{ immediate: true }
);
const dictionaryInfo = ref({});
const getDictionaryInfo = () => {
getdemandtypelist().then((res) => {
dictionaryInfo.value = res.data;
});
};
const getCodeList = (code) => {
getDemanddiclist({
type: "demand",
code: code,
}).then((res) => {
codeList.value = res.data.currentPageDatas;
codeList.value.forEach((item) => {
if (item.code == "cooperateway") {
cooperateway.value = codeList.value;
} else if (item.code == "xueke") {
xueke.value = codeList.value;
}
});
});
};
onMounted(() => {
getDictionaryInfo();
getCodeList("cooperateway");
getCodeList("xueke");
if (title.value == "编辑需求" || title.value == "编辑草稿") {
if (form.price == "0") {
form.price = "面议";
}
getDemandDetailInfo({ id: curId.value }).then((res) => {
if (res.success) {
form.title = res.data.name;
form.source = res.data.source;
form.price = res.data.price;
form.province = res.data.province;
form.city = res.data.city;
form.timelimit = res.data.timelimit;
form.context = res.data.context;
form.liaison = res.data.liaison;
form.telephone = res.data.telephone;
form.email = res.data.email;
form.post_code = res.data.post_code;
form.address = res.data.address;
if (res.data.xueke_id !== "") {
form.xueke = res.data.xueke_id.split(",").map(Number);
}
if (res.data.cooperateway_id !== "") {
form.type = res.data.cooperateway_id.split(",").map(Number);
}
}
});
}
getFileList();
});
const setForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
if (form.price == "面议") {
form.price = "0";
} else {
form.price = Number(form.price).toFixed(1);
}
if (title.value == "发布需求") {
addDemand({
id: 0,
name: form.title,
source: form.source,
price: Number(form.price),
province: form.province,
city: form.city,
timelimit: form.timelimit,
context: form.context,
liaison: form.liaison,
telephone: form.telephone,
email: form.email,
address: form.address,
post_code: form.post_code,
check_state: 0,
xueke_id: form.xueke.toString(),
cooperateway_id: form.type.toString(),
show_count: 0,
fileModels: form.fileModels,
createuser: "00000000-0000-0000-0000-000000000000",
}).then((res) => {
if (res.success) {
ElMessage.success({ message: `发布需求成功` });
router.push({
path: "/demands",
});
} else {
ElMessage.error({ message: `发布需求失败` });
}
});
} else if (title.value == "编辑需求" || title.value == "编辑草稿") {
updateDemand({
id: curId.value,
name: form.title,
source: form.source,
price: Number(form.price),
province: form.province,
city: form.city,
timelimit: form.timelimit,
context: form.context,
liaison: form.liaison,
telephone: form.telephone,
email: form.email,
address: form.address,
post_code: form.post_code,
check_state: 0,
xueke_id: form.xueke.toString(),
cooperateway_id: form.type.toString(),
show_count: 0,
createuser: "00000000-0000-0000-0000-000000000000",
}).then((res) => {
if (res.success) {
ElMessage.success({ message: `编辑需求成功` });
router.push({
path: "/demands",
});
} else {
ElMessage.error({ message: `编辑需求失败` });
}
});
}
}
});
};
const keepForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
if (form.price == "面议") {
form.price = "0";
} else {
form.price = Number(form.price).toFixed(1);
}
keepDemand({
id: 0,
name: form.title,
source: form.source,
price: Number(form.price),
province: form.province,
city: form.city,
timelimit: form.timelimit,
context: form.context,
liaison: form.liaison,
telephone: form.telephone,
email: form.email,
address: form.address,
post_code: form.post_code,
check_state: 2,
xueke_id: form.xueke.toString(),
cooperateway_id: form.type.toString(),
show_count: 0,
createuser: "00000000-0000-0000-0000-000000000000",
fileModels: form.fileModels
}).then((res) => {
if (res.success) {
ElMessage.success({ message: `保存草稿成功` });
router.push({
path: "/draft",
query: {
title: "发布需求",
},
});
} else {
ElMessage.error({ message: `保存草稿失败` });
}
});
formEl.resetFields();
} else {
}
});
};
const getFileList = () => {
getFiles({
type: 0, //0需求 1成果
infoid: curId.value,
filetype: -1, //-1不分类,0图片 1视频 2文档
}).then((res) => {
if (res.data) {
files.value = res.data;
files.value.splice(0, 1);
files.value.forEach((item) => {
if (item.file_type == 0) {
item.file_type = "图片";
} else if (item.file_type == 1) {
item.file_type = "视频";
} else {
item.file_type = "文档";
}
});
}
});
};
const close = () => {
fileDialog.value = false;
};
const delFile = (id, index) => {
if (title.value == "编辑需求" || title.value == "编辑草稿") {
delFiles({ id: id }).then((res) => {
getFileList();
});
} else if (title.value == "发布需求") {
files.value.splice(index, 1);
}
uploadFile;
};
const uploadFile = (item) => {
let formData = new FormData();
formData.append("files", item);
upload(formData).then((res) => {
if (res.success) {
if (title.value == "编辑需求" || title.value == "编辑草稿") {
res.data.forEach((item) => {
addFile(item.fileName, item.fileUrl, item.fileType);
});
} else if (title.value == "发布需求") {
res.data.forEach((item) => {
const loadFile = {
file_type: item.fileType,
file_name: item.fileName,
file_url: item.fileUrl,
};
const loadFiles = {
file_type: item.fileType==0 ? "图片" : item.fileType==1 ? "视频" : "文档",
file_name: item.fileName,
file_url: item.fileUrl,
};
files.value.push(loadFiles);
form.fileModels.push(loadFile);
});
}
} else {
fileDialog.value = true;
msg.value = "不支持此类型文件上传";
}
});
};
const addFile = (fileName, fileUrl, fileType) => {
addFiles({
info_id: curId.value,
type_id: 0, //成果1 需求0
file_type: fileType,
file_name: fileName,
file_url: fileUrl,
}).then((res) => {
if (res.success) {
getFileList();
}
});
};
const showImg = (url) => {
const strArr = url.split(".");
// const addType = strArr[1];
const addType = strArr[1];
if (["png", "jpg", "jpeg"].includes(addType)) {
dialogImageUrl.value = url;
dialogImg.value = true;
}
};
const lockValue = (province) => {
form.province = province;
};
const lock = (city) => {
form.city = city;
};
</script>
<style lang="less" scoped>
.demandBox {
width: 74.75%;
padding-bottom: 50px;
background-color: #ffffff;
.titleBox {
width: 100%;
height: 50px;
display: flex;
padding: 18px 47px 0px 30px;
font-size: 16px;
color: #262626;
justify-content: space-between;
}
.line {
width: 100%;
height: 1px;
background-color: #dddddd;
}
.form {
padding-left: 80px;
padding-top: 50px;
:deep(.el-input__wrapper) {
height: 40px;
}
.location {
.el-select {
margin-right: 20px;
}
}
.province {
margin-right: 20px;
}
.uploadBox {
max-width: 400px;
width: 100%;
display: flex;
flex-direction: column;
.uploadList {
margin-top: 20px;
width: 100%;
background-color: #f7f8fb;
border-radius: 2px;
ul {
padding: 0px;
display: flex;
justify-content: space-around;
li {
list-style: none;
font-size: 12px;
color: #666666;
span:hover {
cursor: pointer;
color: #abb0b6;
}
}
}
.files {
justify-content: flex-start;
li:first-child {
margin-left: 15px;
width: 120px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
}
.fileType {
text-align: center;
margin-left: 50px;
width: 50px;
}
.fileAction {
text-align: center;
margin-left: 77px;
width: 60px;
}
}
.uploadTitle {
li {
color: #999999;
}
}
}
}
.upload {
background-color: #005bc5;
width: 137px;
height: 38px;
}
.subButton {
width: 180px;
height: 40px;
background-color: #005bc5;
border-radius: 3px;
margin-top: 34px;
font-size: 16px;
}
.subButton:hover {
color: #abb0b6;
}
.saveButton {
width: 180px;
height: 40px;
background-color: white;
border-radius: 3px;
margin-top: 34px;
font-size: 16px;
color: #262626;
border-color: #b1b7bf;
}
.saveButton:hover {
color: #abb0b6;
}
}
.notice {
display: flex;
margin-left: 100px;
align-items: center;
color: #999999;
margin-top: 40px;
span {
border: 1px solid #999999;
border-color: #999999;
border-radius: 50%;
width: 20px;
height: 20px;
display: block;
text-align: center;
line-height: 18px;
color: #999999;
margin-right: 10px;
}
}
}
</style>

本文介绍了一个用于发布和编辑需求的Vue组件,该组件利用Element Plus库实现了需求表单的功能,包括选择地区、填写需求详情及附件上传等。组件还支持不同场景如发布需求、编辑需求或编辑草稿。
3275

被折叠的 条评论
为什么被折叠?



