mirror of
https://github.com/nagisa77/OpenIsle.git
synced 2026-06-07 02:27:34 +08:00
fix: 分类提案简化用户输入
This commit is contained in:
@@ -75,10 +75,7 @@ public class PostController {
|
|||||||
req.getOptions(),
|
req.getOptions(),
|
||||||
req.getMultiple(),
|
req.getMultiple(),
|
||||||
req.getProposedName(),
|
req.getProposedName(),
|
||||||
req.getProposedSlug(),
|
req.getProposalDescription()
|
||||||
req.getProposalDescription(),
|
|
||||||
req.getApproveThreshold(),
|
|
||||||
req.getQuorum()
|
|
||||||
);
|
);
|
||||||
draftService.deleteDraft(auth.getName());
|
draftService.deleteDraft(auth.getName());
|
||||||
PostDetailDto dto = postMapper.toDetailDto(post, auth.getName());
|
PostDetailDto dto = postMapper.toDetailDto(post, auth.getName());
|
||||||
|
|||||||
@@ -31,8 +31,5 @@ public class PostRequest {
|
|||||||
|
|
||||||
// fields for category proposal posts
|
// fields for category proposal posts
|
||||||
private String proposedName;
|
private String proposedName;
|
||||||
private String proposedSlug;
|
|
||||||
private String proposalDescription;
|
private String proposalDescription;
|
||||||
private Integer approveThreshold;
|
|
||||||
private Integer quorum;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,59 +7,53 @@ import jakarta.persistence.Enumerated;
|
|||||||
import jakarta.persistence.Index;
|
import jakarta.persistence.Index;
|
||||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A specialized post type used for proposing new categories.
|
* A specialized post type used for proposing new categories.
|
||||||
* It reuses poll mechanics (participants, votes, endTime) by extending PollPost.
|
* It reuses poll mechanics (participants, votes, endTime) by extending PollPost.
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "category_proposal_posts", indexes = {
|
@Table(
|
||||||
@Index(name = "idx_category_proposal_posts_status", columnList = "status"),
|
name = "category_proposal_posts",
|
||||||
@Index(name = "idx_category_proposal_posts_slug", columnList = "proposed_slug", unique = true)
|
indexes = { @Index(name = "idx_category_proposal_posts_status", columnList = "status") }
|
||||||
})
|
)
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@PrimaryKeyJoinColumn(name = "post_id")
|
@PrimaryKeyJoinColumn(name = "post_id")
|
||||||
public class CategoryProposalPost extends PollPost {
|
public class CategoryProposalPost extends PollPost {
|
||||||
|
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
@Column(name = "status", nullable = false)
|
@Column(name = "status", nullable = false)
|
||||||
private CategoryProposalStatus proposalStatus = CategoryProposalStatus.PENDING;
|
private CategoryProposalStatus proposalStatus = CategoryProposalStatus.PENDING;
|
||||||
|
|
||||||
@Column(name = "proposed_name", nullable = false)
|
@Column(name = "proposed_name", nullable = false, unique = true)
|
||||||
private String proposedName;
|
private String proposedName;
|
||||||
|
|
||||||
@Column(name = "proposed_slug", nullable = false, unique = true)
|
@Column(name = "description")
|
||||||
private String proposedSlug;
|
private String description;
|
||||||
|
|
||||||
@Column(name = "description")
|
// Approval threshold as percentage (0-100), default 60
|
||||||
private String description;
|
@Column(name = "approve_threshold", nullable = false)
|
||||||
|
private int approveThreshold = 60;
|
||||||
|
|
||||||
// Approval threshold as percentage (0-100), default 60
|
// Minimum number of participants required to meet quorum
|
||||||
@Column(name = "approve_threshold", nullable = false)
|
@Column(name = "quorum", nullable = false)
|
||||||
private int approveThreshold = 60;
|
private int quorum = 10;
|
||||||
|
|
||||||
// Minimum number of participants required to meet quorum
|
// Optional voting start time (end time inherited from PollPost)
|
||||||
@Column(name = "quorum", nullable = false)
|
@Column(name = "start_at")
|
||||||
private int quorum = 10;
|
private LocalDateTime startAt;
|
||||||
|
|
||||||
// Optional voting start time (end time inherited from PollPost)
|
// Snapshot of poll results at finalization (e.g., JSON)
|
||||||
@Column(name = "start_at")
|
@Column(name = "result_snapshot", columnDefinition = "TEXT")
|
||||||
private LocalDateTime startAt;
|
private String resultSnapshot;
|
||||||
|
|
||||||
// Snapshot of poll results at finalization (e.g., JSON)
|
// Reason when proposal is rejected
|
||||||
@Column(name = "result_snapshot", columnDefinition = "TEXT")
|
@Column(name = "reject_reason")
|
||||||
private String resultSnapshot;
|
private String rejectReason;
|
||||||
|
|
||||||
// Reason when proposal is rejected
|
|
||||||
@Column(name = "reject_reason")
|
|
||||||
private String rejectReason;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,18 @@ package com.openisle.repository;
|
|||||||
|
|
||||||
import com.openisle.model.CategoryProposalPost;
|
import com.openisle.model.CategoryProposalPost;
|
||||||
import com.openisle.model.CategoryProposalStatus;
|
import com.openisle.model.CategoryProposalStatus;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface CategoryProposalPostRepository extends JpaRepository<CategoryProposalPost, Long> {
|
public interface CategoryProposalPostRepository extends JpaRepository<CategoryProposalPost, Long> {
|
||||||
List<CategoryProposalPost> findByEndTimeAfterAndProposalStatus(LocalDateTime now, CategoryProposalStatus status);
|
List<CategoryProposalPost> findByEndTimeAfterAndProposalStatus(
|
||||||
List<CategoryProposalPost> findByEndTimeBeforeAndProposalStatus(LocalDateTime now, CategoryProposalStatus status);
|
LocalDateTime now,
|
||||||
boolean existsByProposedSlug(String proposedSlug);
|
CategoryProposalStatus status
|
||||||
|
);
|
||||||
|
List<CategoryProposalPost> findByEndTimeBeforeAndProposalStatus(
|
||||||
|
LocalDateTime now,
|
||||||
|
CategoryProposalStatus status
|
||||||
|
);
|
||||||
|
boolean existsByProposedNameIgnoreCase(String proposedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ public class PostService {
|
|||||||
|
|
||||||
private final SearchIndexEventPublisher searchIndexEventPublisher;
|
private final SearchIndexEventPublisher searchIndexEventPublisher;
|
||||||
|
|
||||||
|
private static final int DEFAULT_PROPOSAL_APPROVE_THRESHOLD = 60;
|
||||||
|
private static final int DEFAULT_PROPOSAL_QUORUM = 10;
|
||||||
|
private static final long DEFAULT_PROPOSAL_DURATION_DAYS = 3;
|
||||||
|
private static final List<String> DEFAULT_PROPOSAL_OPTIONS = List.of("同意", "反对");
|
||||||
|
|
||||||
@Value("${app.website-url:https://www.open-isle.com}")
|
@Value("${app.website-url:https://www.open-isle.com}")
|
||||||
private String websiteUrl;
|
private String websiteUrl;
|
||||||
|
|
||||||
@@ -253,10 +258,7 @@ public class PostService {
|
|||||||
java.util.List<String> options,
|
java.util.List<String> options,
|
||||||
Boolean multiple,
|
Boolean multiple,
|
||||||
String proposedName,
|
String proposedName,
|
||||||
String proposedSlug,
|
String proposalDescription
|
||||||
String proposalDescription,
|
|
||||||
Integer approveThreshold,
|
|
||||||
Integer quorum
|
|
||||||
) {
|
) {
|
||||||
// 限制访问次数
|
// 限制访问次数
|
||||||
boolean limitResult = postRateLimit(username);
|
boolean limitResult = postRateLimit(username);
|
||||||
@@ -307,35 +309,18 @@ public class PostService {
|
|||||||
if (proposedName == null || proposedName.isBlank()) {
|
if (proposedName == null || proposedName.isBlank()) {
|
||||||
throw new IllegalArgumentException("Proposed name required");
|
throw new IllegalArgumentException("Proposed name required");
|
||||||
}
|
}
|
||||||
if (proposedSlug == null || proposedSlug.isBlank()) {
|
String normalizedName = proposedName.trim();
|
||||||
throw new IllegalArgumentException("Proposed slug required");
|
if (categoryProposalPostRepository.existsByProposedNameIgnoreCase(normalizedName)) {
|
||||||
|
throw new IllegalArgumentException("Proposed name already exists: " + normalizedName);
|
||||||
}
|
}
|
||||||
if (categoryProposalPostRepository.existsByProposedSlug(proposedSlug)) {
|
cp.setProposedName(normalizedName);
|
||||||
throw new IllegalArgumentException("Proposed slug already exists: " + proposedSlug);
|
|
||||||
}
|
|
||||||
cp.setProposedName(proposedName);
|
|
||||||
cp.setProposedSlug(proposedSlug);
|
|
||||||
cp.setDescription(proposalDescription);
|
cp.setDescription(proposalDescription);
|
||||||
if (approveThreshold != null) {
|
cp.setApproveThreshold(DEFAULT_PROPOSAL_APPROVE_THRESHOLD);
|
||||||
if (approveThreshold < 0 || approveThreshold > 100) {
|
cp.setQuorum(DEFAULT_PROPOSAL_QUORUM);
|
||||||
throw new IllegalArgumentException("approveThreshold must be between 0 and 100");
|
LocalDateTime now = LocalDateTime.now();
|
||||||
}
|
cp.setStartAt(now);
|
||||||
cp.setApproveThreshold(approveThreshold);
|
cp.setEndTime(now.plusDays(DEFAULT_PROPOSAL_DURATION_DAYS));
|
||||||
}
|
cp.setOptions(DEFAULT_PROPOSAL_OPTIONS);
|
||||||
if (quorum != null) {
|
|
||||||
if (quorum < 0) {
|
|
||||||
throw new IllegalArgumentException("quorum must be >= 0");
|
|
||||||
}
|
|
||||||
cp.setQuorum(quorum);
|
|
||||||
}
|
|
||||||
cp.setStartAt(startTime);
|
|
||||||
cp.setEndTime(endTime);
|
|
||||||
// default yes/no options if not provided
|
|
||||||
if (options == null || options.size() < 2) {
|
|
||||||
cp.setOptions(List.of("同意", "反对"));
|
|
||||||
} else {
|
|
||||||
cp.setOptions(options);
|
|
||||||
}
|
|
||||||
cp.setMultiple(false);
|
cp.setMultiple(false);
|
||||||
post = cp;
|
post = cp;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
ALTER TABLE category_proposal_posts
|
||||||
|
DROP INDEX idx_category_proposal_posts_slug;
|
||||||
|
|
||||||
|
ALTER TABLE category_proposal_posts
|
||||||
|
DROP COLUMN proposed_slug;
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_category_proposal_posts_name
|
||||||
|
ON category_proposal_posts (proposed_name);
|
||||||
@@ -4,67 +4,19 @@
|
|||||||
<span class="proposal-row-title">拟议分类名称</span>
|
<span class="proposal-row-title">拟议分类名称</span>
|
||||||
<BaseInput v-model="data.proposedName" placeholder="请输入分类名称" />
|
<BaseInput v-model="data.proposedName" placeholder="请输入分类名称" />
|
||||||
</div>
|
</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">
|
<div class="proposal-row">
|
||||||
<span class="proposal-row-title">提案描述</span>
|
<span class="proposal-row-title">提案描述</span>
|
||||||
<BaseInput v-model="data.proposalDescription" placeholder="简要说明提案目的与理由" />
|
<BaseInput v-model="data.proposalDescription" placeholder="简要说明提案目的与理由" />
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import 'flatpickr/dist/flatpickr.css'
|
|
||||||
import FlatPickr from 'vue-flatpickr-component'
|
|
||||||
import BaseInput from '~/components/BaseInput.vue'
|
import BaseInput from '~/components/BaseInput.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
data: { type: Object, required: true },
|
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>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -75,55 +27,16 @@ const removeOption = (idx) => {
|
|||||||
gap: 20px;
|
gap: 20px;
|
||||||
margin-bottom: 200px;
|
margin-bottom: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proposal-row-title {
|
.proposal-row-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proposal-row {
|
.proposal-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
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>
|
</style>
|
||||||
|
|||||||
@@ -80,12 +80,7 @@ const poll = reactive({
|
|||||||
})
|
})
|
||||||
const proposal = reactive({
|
const proposal = reactive({
|
||||||
proposedName: '',
|
proposedName: '',
|
||||||
proposedSlug: '',
|
|
||||||
proposalDescription: '',
|
proposalDescription: '',
|
||||||
approveThreshold: 60,
|
|
||||||
quorum: 10,
|
|
||||||
endTime: null,
|
|
||||||
options: ['同意', '反对'],
|
|
||||||
})
|
})
|
||||||
const startTime = ref(null)
|
const startTime = ref(null)
|
||||||
const isWaitingPosting = ref(false)
|
const isWaitingPosting = ref(false)
|
||||||
@@ -135,12 +130,7 @@ const clearPost = async () => {
|
|||||||
poll.endTime = null
|
poll.endTime = null
|
||||||
poll.multiple = false
|
poll.multiple = false
|
||||||
proposal.proposedName = ''
|
proposal.proposedName = ''
|
||||||
proposal.proposedSlug = ''
|
|
||||||
proposal.proposalDescription = ''
|
proposal.proposalDescription = ''
|
||||||
proposal.approveThreshold = 60
|
|
||||||
proposal.quorum = 10
|
|
||||||
proposal.endTime = null
|
|
||||||
proposal.options = ['同意', '反对']
|
|
||||||
|
|
||||||
// 删除草稿
|
// 删除草稿
|
||||||
const token = getToken()
|
const token = getToken()
|
||||||
@@ -306,26 +296,6 @@ const submitPost = async () => {
|
|||||||
toast.error('请填写拟议分类名称')
|
toast.error('请填写拟议分类名称')
|
||||||
return
|
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 {
|
try {
|
||||||
const token = getToken()
|
const token = getToken()
|
||||||
@@ -347,51 +317,43 @@ const submitPost = async () => {
|
|||||||
}
|
}
|
||||||
prizeIconUrl = uploadData.data.url
|
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`, {
|
const res = await fetch(`${API_BASE_URL}/api/posts`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(payload),
|
||||||
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,
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
|
|||||||
Reference in New Issue
Block a user