8 changed files with 513 additions and 5 deletions
-
280package-lock.json
-
1package.json
-
2src/apis/article.js
-
0src/apis/user.js
-
2src/components/home/AsideMenu.vue
-
11src/stores/article.js
-
8src/stores/user.js
-
214src/views/Article/Article.vue
@ -1,3 +1,3 @@ |
|||
import { request } from "@/utils/request"; |
|||
|
|||
export const apiAddArticle = async (article) =>request.post(`/addArticle`,article); |
|||
export const apiAddArticle = async (articleForm) =>request.post(`/addArticle`,articleForm); |
@ -0,0 +1,11 @@ |
|||
import { apiAddArticle } from "@/apis/article"; |
|||
import { defineStore } from "pinia"; |
|||
|
|||
export const useArticleStore = defineStore('Atricle',()=>{ |
|||
const addArticle = async(atricleForm) =>{ |
|||
return await apiAddArticle(atricleForm) |
|||
} |
|||
return{ |
|||
addArticle |
|||
} |
|||
}) |
@ -0,0 +1,8 @@ |
|||
import { defineStore } from "pinia"; |
|||
import { ref } from "vue"; |
|||
export const useUserStore = defineStore('User',()=>{ |
|||
let userId = ref(1) |
|||
return{ |
|||
userId |
|||
} |
|||
}) |
@ -1,5 +1,213 @@ |
|||
<template> |
|||
<div> |
|||
aaaa |
|||
<el-form :model="form" label-width="auto" :rules="rules" ref="elFormRef" style="max-width: 600px"> |
|||
<el-form-item label="文章标题" prop="articleTitle"> |
|||
<el-input v-model="form.articleTitle" /> |
|||
</el-form-item> |
|||
<el-form-item label="文章内容" prop="articleContent"> |
|||
<el-input v-model="form.articleContent" type="textarea" /> |
|||
</el-form-item> |
|||
<el-form-item label="是否发起投票"> |
|||
<el-switch v-model="form.voteStatus" style="--el-switch-on-color: red" @change="handleVoteToggle" /> |
|||
</el-form-item> |
|||
<div class="vote-section" v-show="form.voteStatus"> |
|||
<el-form-item label="投票标题" prop="voteTitle"> |
|||
<el-input v-model="form.voteTitle" placeholder="请填写投票标题,最多24个字" /> |
|||
</el-form-item> |
|||
<el-form-item label="选项" required> |
|||
<div class="vote-options-container"> |
|||
<div v-for="(option, index) in form.optionList" :key="index" class="vote-option-item"> |
|||
<!-- <el-input v-model="option.optionContent" :placeholder="'选项' + (index + 1) + ',最多24个字'" /> --> |
|||
<el-form-item :prop="`optionList.${index}.optionContent`" :rules="[ |
|||
{ required: true, message: `选项${index + 1}不能为空`, trigger: 'blur' }, |
|||
{ max: 24, message: '最多24个字', trigger: 'blur' } |
|||
]" style="flex: 1"> |
|||
<el-input v-model="option.optionContent" :placeholder="'选项' + (index + 1) + ',最多24个字'" /> |
|||
</el-form-item> |
|||
<el-button v-show="index > 1" @click="removeOption(index)" class="remove-btn" type="danger" :icon="Delete" |
|||
circle /> |
|||
</div> |
|||
<el-button @click="addOption" type="primary" plain class="add-option-btn"> |
|||
<el-icon> |
|||
<Plus /> |
|||
</el-icon>添加选项 |
|||
</el-button> |
|||
</div> |
|||
</el-form-item> |
|||
<el-form-item label="支持多选"> |
|||
<el-switch v-model="form.multiOption" style="--el-switch-on-color: red" /> |
|||
</el-form-item> |
|||
<el-form-item label="投票截止时间" prop="deadlineTime"> |
|||
<el-date-picker v-model="form.deadlineTime" type="datetime" placeholder="选择时间" format="YYYY/MM/DD HH:mm:ss" /> |
|||
</el-form-item> |
|||
</div> |
|||
</template> |
|||
<el-form-item> |
|||
<div class="publish-article"> |
|||
<el-button type="primary" @click="onSubmit">发表</el-button> |
|||
</div> |
|||
</el-form-item> |
|||
</el-form> |
|||
</template> |
|||
<script setup> |
|||
import { reactive, ref } from 'vue' |
|||
import { Delete, Plus } from '@element-plus/icons-vue' |
|||
import { ElMessage, ElMessageBox, ElForm } from 'element-plus' |
|||
import { useArticleStore } from '@/stores/article' |
|||
import { useUserStore } from '@/stores/user' |
|||
const elFormRef = ref() |
|||
let optionIndex = ref(3) |
|||
// 切换投票开关 |
|||
const handleVoteToggle = (value) => { |
|||
if (value) { |
|||
optionIndex.value = 3 |
|||
form.voteTitle = ''; |
|||
form.optionList = [ |
|||
{ index: 1, optionContent: '' }, |
|||
{ index: 2, optionContent: '' } |
|||
]; |
|||
form.deadlineTime = ''; |
|||
} else { |
|||
form.optionList = [] |
|||
} |
|||
}; |
|||
// 添加选项 |
|||
const addOption = () => { |
|||
if (form.optionList.length >= 20) { |
|||
ElMessageBox.alert('最多添加20个选项', '提示', { |
|||
confirmButtonText: '确认', |
|||
}); |
|||
return |
|||
} |
|||
form.optionList.push({ index: optionIndex.value++, optionContent: '' }); |
|||
}; |
|||
// 移除选项 |
|||
const removeOption = (index) => { |
|||
console.log(index) |
|||
if (form.optionList.length > 2) { |
|||
form.optionList.splice(index, 1); |
|||
} |
|||
}; |
|||
const form = reactive({ |
|||
articleTitle: '', |
|||
articleContent: '', |
|||
voteStatus: false, |
|||
voteTitle: '', |
|||
optionList: [], |
|||
deadlineTime: '' |
|||
}) |
|||
const rules = reactive({ |
|||
articleTitle: [ |
|||
{ required: true, message: '请输入文章标题', trigger: 'blur' }, |
|||
{ min: 3, max: 50, message: '标题长度在5~100字范围内', trigger: 'blur' } |
|||
], |
|||
articleContent: [ |
|||
{ required: true, message: '请输入文章内容', trigger: 'change' } |
|||
], |
|||
voteTitle: [ |
|||
{ |
|||
required: true, |
|||
message: '请输入投票标题', |
|||
trigger: 'blur', |
|||
validator: (rule, value, callback) => { |
|||
if (form.voteStatus && !value) { |
|||
callback(new Error('请输入投票标题')) |
|||
} else { |
|||
callback() |
|||
} |
|||
} |
|||
}, |
|||
{ max: 24, message: '投票标题最多24个字', trigger: 'blur' } |
|||
], |
|||
deadlineTime: [ |
|||
{ |
|||
required: true, |
|||
trigger: 'blur', |
|||
validator: (rule, value, callback) => { |
|||
if (form.voteStatus && !value) { |
|||
callback(new Error('请选择截止日期')) |
|||
} else { |
|||
callback() |
|||
} |
|||
} |
|||
}, |
|||
] |
|||
}) |
|||
const onSubmit = async () => { |
|||
let valid = false |
|||
try { |
|||
valid = await elFormRef.value.validate() |
|||
} catch (error) { |
|||
// 表单验证失败会 throw |
|||
console.log('表单验证失败', error) |
|||
} |
|||
if (valid) { |
|||
console.log('表单验证通过') |
|||
try { |
|||
form.userId = useUserStore().userId |
|||
console.log(form) |
|||
const submitRes = await useArticleStore().addArticle(form) |
|||
console.log('提交成功', submitRes) |
|||
} catch (error) { |
|||
console.log('请求失败',error) |
|||
} |
|||
} |
|||
|
|||
} |
|||
</script> |
|||
<style scoped> |
|||
.vote-section { |
|||
background: #e8f4fe; |
|||
border-left: 4px solid #3498db; |
|||
padding: 20px; |
|||
border-radius: 8px; |
|||
margin-top: 15px; |
|||
margin-bottom: 15px; |
|||
transition: all 0.4s ease; |
|||
} |
|||
|
|||
.vote-options-container { |
|||
display: flex; |
|||
flex-direction: column; |
|||
width: 60%; |
|||
} |
|||
|
|||
.vote-option-item { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 15px; |
|||
border-radius: 8px; |
|||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); |
|||
transition: all 0.3s ease; |
|||
} |
|||
|
|||
.vote-option-item:hover { |
|||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.08); |
|||
transform: translateY(-2px); |
|||
} |
|||
|
|||
.remove-btn { |
|||
margin-left: 5px; |
|||
opacity: 0.7; |
|||
transition: all 0.2s; |
|||
} |
|||
|
|||
.remove-btn:hover { |
|||
color: #e74c3c !important; |
|||
opacity: 1; |
|||
} |
|||
|
|||
.add-option-btn { |
|||
margin-top: 10px; |
|||
display: inline-flex; |
|||
align-items: center; |
|||
transition: all 0.2s; |
|||
border-radius: 6px; |
|||
background-color: #f5f9ff; |
|||
border: 1px dashed #3498db; |
|||
} |
|||
|
|||
.publish-article { |
|||
display: flex; |
|||
justify-content: center; |
|||
width: 100%; |
|||
} |
|||
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue