发布功能可以 存草靠

This commit is contained in:
yml2213
2026-05-23 10:47:41 +08:00
parent 7a52cecf8c
commit ce554432c2
2 changed files with 215 additions and 61 deletions
@@ -431,15 +431,32 @@
font-weight: 800;
}
.publish-actions {
display: grid;
grid-template-columns: 92px minmax(0, 1fr);
gap: 10px;
margin-top: 8px;
}
.reset-btn,
.submit-btn {
height: 44px;
margin-top: 8px;
width: 100%;
border: none !important;
background: #ff6a00 !important;
font-size: 15px;
font-weight: 700;
}
.reset-btn {
border: 1px solid #d7dce3 !important;
background: #fff !important;
color: #4b5563 !important;
}
.submit-btn {
background: #ff6a00 !important;
}
.bottom-nav {
position: fixed;
left: 0;
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { computed, onMounted, reactive, ref, watch } from "vue";
import { useRouter, useRoute } from "vue-router";
import { showToast } from "vant";
import { showDialog, showToast } from "vant";
import { uploadFile } from "@/api/files";
import {
@@ -14,10 +14,42 @@ import {
} from "@/api/listingOptions";
import { createListing } from "@/api/listings";
type PublishForm = {
server_region: string;
face_owner: string;
haf_coin_amount: number | "";
rank_level: string;
secret_kd: string;
fire_level: number | "";
season_insurance: string;
stamina_level: string;
load_level: string;
login_method: string;
online_start: string;
online_end: string;
ban_record: string;
common_regions: string[];
deposit_amount: number | "";
ratio: number | "";
final_price: number;
rent_days: number;
remark: string;
};
interface PublishDraft {
form: PublishForm;
quantityValues: Record<QuantityKey, number>;
quantityModes: Record<QuantityKey, ChargeMode>;
screenshotFiles: Record<ScreenshotKey, string>;
selectedSkins: string[];
}
const draftKey = "hfb.mobile.publish.draft";
const router = useRouter();
const route = useRoute();
const loading = ref(false);
const uploading = ref(false);
const suppressDraftSave = ref(false);
const publishOptions = ref<ListingPublishOptions>(defaultListingPublishOptions);
function isNavActive(path: string) {
@@ -25,13 +57,14 @@ function isNavActive(path: string) {
return route.path.startsWith(path);
}
const form = reactive({
function defaultForm(): PublishForm {
return {
server_region: "",
face_owner: "",
haf_coin_amount: "" as number | "",
haf_coin_amount: "",
rank_level: "",
secret_kd: "",
fire_level: "" as number | "",
fire_level: "",
season_insurance: "",
stamina_level: "",
load_level: "",
@@ -39,39 +72,54 @@ const form = reactive({
online_start: "",
online_end: "",
ban_record: "",
common_regions: [] as string[],
deposit_amount: "" as number | "",
ratio: "" as number | "",
common_regions: [],
deposit_amount: "",
ratio: "",
final_price: 0,
rent_days: 0,
remark: "",
});
};
}
const quantityValues = reactive<Record<QuantityKey, number>>({
function defaultQuantityValues(): Record<QuantityKey, number> {
return {
awmAmmo: 0,
helmet6: 0,
armor6: 0,
kit5: 0,
level6Ammo: 0,
gridCard9: 0,
});
};
}
const quantityModes = reactive<Record<QuantityKey, ChargeMode>>({
function defaultQuantityModes(): Record<QuantityKey, ChargeMode> {
return {
awmAmmo: "收费",
helmet6: "收费",
armor6: "收费",
kit5: "收费",
level6Ammo: "收费",
gridCard9: "收费",
});
};
}
const screenshotFiles = reactive<Record<ScreenshotKey, string>>({
function defaultScreenshotFiles(): Record<ScreenshotKey, string> {
return {
coin: "",
gameId: "",
totalAsset: "",
tencentSecurity: "",
skin: "",
});
};
}
const form = reactive<PublishForm>(defaultForm());
const quantityValues = reactive<Record<QuantityKey, number>>(defaultQuantityValues());
const quantityModes = reactive<Record<QuantityKey, ChargeMode>>(defaultQuantityModes());
const screenshotFiles = reactive<Record<ScreenshotKey, string>>(defaultScreenshotFiles());
const selectedSkins = ref<string[]>([]);
const fileInput = ref<HTMLInputElement | null>(null);
@@ -96,7 +144,18 @@ const dailyLossText = computed(() =>
form.rent_days ? calculateDailyLoss(Number(form.haf_coin_amount || 0)) : ""
);
onMounted(loadPublishOptions);
onMounted(() => {
restoreDraft();
loadPublishOptions();
});
watch(
[form, quantityValues, quantityModes, screenshotFiles, selectedSkins],
() => {
saveDraft();
},
{ deep: true }
);
async function loadPublishOptions() {
try {
@@ -106,6 +165,74 @@ async function loadPublishOptions() {
}
}
function buildDraft(): PublishDraft {
return {
form: {
...form,
common_regions: [...form.common_regions],
},
quantityValues: { ...quantityValues },
quantityModes: { ...quantityModes },
screenshotFiles: { ...screenshotFiles },
selectedSkins: [...selectedSkins.value],
};
}
function saveDraft() {
if (suppressDraftSave.value) return;
localStorage.setItem(draftKey, JSON.stringify(buildDraft()));
}
function restoreDraft() {
const raw = localStorage.getItem(draftKey);
if (!raw) return;
try {
const draft = JSON.parse(raw) as Partial<PublishDraft>;
Object.assign(form, defaultForm(), draft.form || {});
form.common_regions = Array.isArray(draft.form?.common_regions)
? [...draft.form.common_regions]
: [];
Object.assign(quantityValues, defaultQuantityValues(), draft.quantityValues || {});
Object.assign(quantityModes, defaultQuantityModes(), draft.quantityModes || {});
Object.assign(screenshotFiles, defaultScreenshotFiles(), draft.screenshotFiles || {});
selectedSkins.value = Array.isArray(draft.selectedSkins)
? draft.selectedSkins.filter((skin): skin is string => typeof skin === "string")
: [];
} catch {
localStorage.removeItem(draftKey);
}
}
function resetDraftState() {
Object.assign(form, defaultForm());
Object.assign(quantityValues, defaultQuantityValues());
Object.assign(quantityModes, defaultQuantityModes());
Object.assign(screenshotFiles, defaultScreenshotFiles());
selectedSkins.value = [];
activeUploadKey.value = "coin";
}
async function handleResetDraft() {
try {
await showDialog({
title: "重置发布内容",
message: "将清空当前填写内容和本地草稿。",
confirmButtonText: "重置",
cancelButtonText: "取消",
showCancelButton: true,
});
} catch {
return;
}
suppressDraftSave.value = true;
resetDraftState();
localStorage.removeItem(draftKey);
showToast({ message: "已重置", icon: "passed" });
window.setTimeout(() => {
suppressDraftSave.value = false;
});
}
function selectRadio<T extends string>(value: T, setter: (value: T) => void) {
setter(value);
}
@@ -158,7 +285,7 @@ function handleFireLevelInput(value: string | number) {
form.fire_level = "";
return;
}
form.fire_level = Math.max(38, Math.trunc(level));
form.fire_level = Math.trunc(level);
}
function calculatePrice() {
@@ -207,6 +334,7 @@ async function handleSubmit() {
min_rent_hours: 24,
max_rent_hours: rentDays * 24,
});
localStorage.removeItem(draftKey);
showToast({ message: "发布成功", icon: "passed" });
await router.push("/m/profile");
} catch (error) {
@@ -671,9 +799,17 @@ function readError(error: unknown, fallback: string) {
/>
</div>
<div class="publish-actions">
<van-button
round
class="reset-btn"
:disabled="loading"
@click="handleResetDraft"
>
重置
</van-button>
<van-button
type="primary"
block
round
class="submit-btn"
:loading="loading"
@@ -682,6 +818,7 @@ function readError(error: unknown, fallback: string) {
>
保存发布
</van-button>
</div>
</section>
<nav class="bottom-nav">