mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-03-16 00:50:47 +08:00
fix: 分类提案简化用户输入
This commit is contained in:
@@ -4,67 +4,19 @@
|
||||
<span class="proposal-row-title">拟议分类名称</span>
|
||||
<BaseInput v-model="data.proposedName" placeholder="请输入分类名称" />
|
||||
</div>
|
||||
<div class="proposal-row">
|
||||
<span class="proposal-row-title">拟议分类 Slug</span>
|
||||
<BaseInput v-model="data.proposedSlug" placeholder="小写短横线分隔,如: tech-news" />
|
||||
</div>
|
||||
<div class="proposal-row">
|
||||
<span class="proposal-row-title">提案描述</span>
|
||||
<BaseInput v-model="data.proposalDescription" placeholder="简要说明提案目的与理由" />
|
||||
</div>
|
||||
<div class="proposal-row two-col">
|
||||
<div class="proposal-col">
|
||||
<span class="proposal-row-title">通过阈值(%)</span>
|
||||
<input
|
||||
class="number-input"
|
||||
type="number"
|
||||
v-model.number="data.approveThreshold"
|
||||
min="0"
|
||||
max="100"
|
||||
/>
|
||||
</div>
|
||||
<div class="proposal-col">
|
||||
<span class="proposal-row-title">法定最小参与数</span>
|
||||
<input class="number-input" type="number" v-model.number="data.quorum" min="0" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="proposal-row">
|
||||
<span class="proposal-row-title">投票结束时间</span>
|
||||
<client-only>
|
||||
<flat-pickr v-model="data.endTime" :config="dateConfig" class="time-picker" />
|
||||
</client-only>
|
||||
</div>
|
||||
<div class="proposal-row">
|
||||
<span class="proposal-row-title">投票选项</span>
|
||||
<div class="poll-option-item" v-for="(opt, idx) in data.options" :key="idx">
|
||||
<BaseInput v-model="data.options[idx]" placeholder="选项内容" />
|
||||
<close-icon class="remove-option-icon" @click="removeOption(idx)" />
|
||||
</div>
|
||||
<div class="add-option" @click="addOption">添加选项</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import 'flatpickr/dist/flatpickr.css'
|
||||
import FlatPickr from 'vue-flatpickr-component'
|
||||
import BaseInput from '~/components/BaseInput.vue'
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
data: { type: Object, required: true },
|
||||
})
|
||||
|
||||
const dateConfig = { enableTime: true, time_24hr: true, dateFormat: 'Y-m-d H:i' }
|
||||
|
||||
const addOption = () => {
|
||||
props.data.options.push('')
|
||||
}
|
||||
|
||||
const removeOption = (idx) => {
|
||||
if (props.data.options.length > 2) {
|
||||
props.data.options.splice(idx, 1)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -75,55 +27,16 @@ const removeOption = (idx) => {
|
||||
gap: 20px;
|
||||
margin-bottom: 200px;
|
||||
}
|
||||
|
||||
.proposal-row-title {
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.proposal-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.two-col {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
.proposal-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.number-input {
|
||||
max-width: 120px;
|
||||
height: 30px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 0 10px;
|
||||
font-size: 16px;
|
||||
color: var(--text-color);
|
||||
background-color: var(--lottery-background-color);
|
||||
}
|
||||
.poll-option-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.remove-option-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
.add-option {
|
||||
color: var(--primary-color);
|
||||
cursor: pointer;
|
||||
width: fit-content;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.time-picker {
|
||||
max-width: 200px;
|
||||
height: 30px;
|
||||
background-color: var(--lottery-background-color);
|
||||
border-radius: 5px;
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -80,12 +80,7 @@ const poll = reactive({
|
||||
})
|
||||
const proposal = reactive({
|
||||
proposedName: '',
|
||||
proposedSlug: '',
|
||||
proposalDescription: '',
|
||||
approveThreshold: 60,
|
||||
quorum: 10,
|
||||
endTime: null,
|
||||
options: ['同意', '反对'],
|
||||
})
|
||||
const startTime = ref(null)
|
||||
const isWaitingPosting = ref(false)
|
||||
@@ -135,12 +130,7 @@ const clearPost = async () => {
|
||||
poll.endTime = null
|
||||
poll.multiple = false
|
||||
proposal.proposedName = ''
|
||||
proposal.proposedSlug = ''
|
||||
proposal.proposalDescription = ''
|
||||
proposal.approveThreshold = 60
|
||||
proposal.quorum = 10
|
||||
proposal.endTime = null
|
||||
proposal.options = ['同意', '反对']
|
||||
|
||||
// 删除草稿
|
||||
const token = getToken()
|
||||
@@ -306,26 +296,6 @@ const submitPost = async () => {
|
||||
toast.error('请填写拟议分类名称')
|
||||
return
|
||||
}
|
||||
if (!proposal.proposedSlug.trim()) {
|
||||
toast.error('请填写拟议分类 Slug')
|
||||
return
|
||||
}
|
||||
if (proposal.approveThreshold < 0 || proposal.approveThreshold > 100) {
|
||||
toast.error('通过阈值需在0到100之间')
|
||||
return
|
||||
}
|
||||
if (proposal.quorum < 0) {
|
||||
toast.error('最小参与数需大于或等于0')
|
||||
return
|
||||
}
|
||||
if (proposal.options.length < 2 || proposal.options.some((o) => !o.trim())) {
|
||||
toast.error('请填写至少两个投票选项')
|
||||
return
|
||||
}
|
||||
if (!proposal.endTime) {
|
||||
toast.error('请选择投票结束时间')
|
||||
return
|
||||
}
|
||||
}
|
||||
try {
|
||||
const token = getToken()
|
||||
@@ -347,51 +317,43 @@ const submitPost = async () => {
|
||||
}
|
||||
prizeIconUrl = uploadData.data.url
|
||||
}
|
||||
const toUtcString = (value) => {
|
||||
if (!value) return undefined
|
||||
return new Date(new Date(value).getTime() + 8.02 * 60 * 60 * 1000).toISOString()
|
||||
}
|
||||
|
||||
const payload = {
|
||||
title: title.value,
|
||||
content: content.value,
|
||||
categoryId: selectedCategory.value,
|
||||
tagIds: selectedTags.value,
|
||||
type: postType.value,
|
||||
}
|
||||
|
||||
if (postType.value === 'LOTTERY') {
|
||||
payload.prizeIcon = prizeIconUrl
|
||||
payload.prizeName = lottery.prizeName
|
||||
payload.prizeCount = lottery.prizeCount
|
||||
payload.prizeDescription = lottery.prizeDescription
|
||||
payload.pointCost = lottery.pointCost
|
||||
payload.startTime = startTime.value ? new Date(startTime.value).toISOString() : undefined
|
||||
payload.endTime = toUtcString(lottery.endTime)
|
||||
} else if (postType.value === 'POLL') {
|
||||
payload.options = poll.options
|
||||
payload.multiple = poll.multiple
|
||||
payload.endTime = toUtcString(poll.endTime)
|
||||
} else if (postType.value === 'PROPOSAL') {
|
||||
payload.proposedName = proposal.proposedName
|
||||
payload.proposalDescription = proposal.proposalDescription
|
||||
}
|
||||
|
||||
const res = await fetch(`${API_BASE_URL}/api/posts`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
title: title.value,
|
||||
content: content.value,
|
||||
categoryId: selectedCategory.value,
|
||||
tagIds: selectedTags.value,
|
||||
type: postType.value,
|
||||
prizeIcon: postType.value === 'LOTTERY' ? prizeIconUrl : undefined,
|
||||
prizeName: postType.value === 'LOTTERY' ? lottery.prizeName : undefined,
|
||||
prizeCount: postType.value === 'LOTTERY' ? lottery.prizeCount : undefined,
|
||||
prizeDescription: postType.value === 'LOTTERY' ? lottery.prizeDescription : undefined,
|
||||
options: postType.value === 'POLL' ? poll.options : undefined,
|
||||
multiple: postType.value === 'POLL' ? poll.multiple : undefined,
|
||||
proposedName: postType.value === 'PROPOSAL' ? proposal.proposedName : undefined,
|
||||
proposedSlug: postType.value === 'PROPOSAL' ? proposal.proposedSlug : undefined,
|
||||
proposalDescription:
|
||||
postType.value === 'PROPOSAL' ? proposal.proposalDescription : undefined,
|
||||
approveThreshold: postType.value === 'PROPOSAL' ? proposal.approveThreshold : undefined,
|
||||
quorum: postType.value === 'PROPOSAL' ? proposal.quorum : undefined,
|
||||
options:
|
||||
postType.value === 'POLL'
|
||||
? poll.options
|
||||
: postType.value === 'PROPOSAL'
|
||||
? proposal.options
|
||||
: undefined,
|
||||
startTime:
|
||||
postType.value === 'LOTTERY' ? new Date(startTime.value).toISOString() : undefined,
|
||||
pointCost: postType.value === 'LOTTERY' ? lottery.pointCost : undefined,
|
||||
// 将时间转换为 UTC+8.5 时区 todo: 需要优化
|
||||
endTime:
|
||||
postType.value === 'LOTTERY'
|
||||
? new Date(new Date(lottery.endTime).getTime() + 8.02 * 60 * 60 * 1000).toISOString()
|
||||
: postType.value === 'POLL'
|
||||
? new Date(new Date(poll.endTime).getTime() + 8.02 * 60 * 60 * 1000).toISOString()
|
||||
: postType.value === 'PROPOSAL'
|
||||
? new Date(
|
||||
new Date(proposal.endTime).getTime() + 8.02 * 60 * 60 * 1000,
|
||||
).toISOString()
|
||||
: undefined,
|
||||
}),
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
const data = await res.json()
|
||||
if (res.ok) {
|
||||
|
||||
Reference in New Issue
Block a user