1
This commit was merged in pull request #1.
This commit is contained in:
@@ -1,13 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { PanelRight } from "lucide-vue-next";
|
||||
import { FileInput, PanelRight, WandSparkles } from "lucide-vue-next";
|
||||
import api from "@/api";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import Tabs from "@/components/ui/tabs/Tabs.vue";
|
||||
import TabsList from "@/components/ui/tabs/TabsList.vue";
|
||||
import TabsTrigger from "@/components/ui/tabs/TabsTrigger.vue";
|
||||
import { useConfigStore, useInfoStore } from "@/stores";
|
||||
import { useDnfHelperStore } from "@/stores/dnfhelper";
|
||||
import type { IConfigEmblem, IConfigEquip, IConfigOath } from "@/stores/config";
|
||||
import type { IHelperInfo } from "@/api/info/type";
|
||||
import ResultPanel from "@/pages/Dcalc/Character/Result/Index.vue";
|
||||
const props = defineProps<{
|
||||
alter: string;
|
||||
@@ -17,14 +31,50 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const infoStore = useInfoStore();
|
||||
const configStore = useConfigStore();
|
||||
const helperStore = useDnfHelperStore();
|
||||
const loading = ref(false);
|
||||
const loadError = ref("");
|
||||
const isExecuting = ref(false);
|
||||
const isMobileLayout = ref(false);
|
||||
const isResultSheetOpen = ref(false);
|
||||
const helperImportOpen = ref(false);
|
||||
const skillImportOpen = ref(false);
|
||||
const helperRoleImportOpen = ref(false);
|
||||
const helperUid = ref("");
|
||||
const skillCode = ref("");
|
||||
const helperImportLoading = ref(false);
|
||||
const skillImportLoading = ref(false);
|
||||
const importStatus = ref("");
|
||||
const importError = ref("");
|
||||
const helperRole = ref<IHelperInfo["roleList"][number]>();
|
||||
|
||||
let mediaQuery: MediaQueryList | null = null;
|
||||
|
||||
type AvatarConfig = Record<
|
||||
string,
|
||||
{
|
||||
id: string;
|
||||
enchant: string;
|
||||
emblem_0: string;
|
||||
emblem_1: string;
|
||||
option: string;
|
||||
}
|
||||
>;
|
||||
|
||||
interface HelperConfigPayload {
|
||||
equips?: Record<string, IConfigEquip>;
|
||||
avatar?: AvatarConfig;
|
||||
avatars?: AvatarConfig;
|
||||
avatarLink?: string;
|
||||
emblems?: Record<string, IConfigEmblem>;
|
||||
fogOathLv?: unknown;
|
||||
oaths?: Record<string, IConfigOath>;
|
||||
}
|
||||
|
||||
interface SkillImportPayload {
|
||||
skills?: typeof configStore.config.skills;
|
||||
}
|
||||
|
||||
const updateMobileLayout = () => {
|
||||
isMobileLayout.value = mediaQuery?.matches ?? false;
|
||||
if (!isMobileLayout.value) {
|
||||
@@ -55,6 +105,7 @@ const loadCharacter = async () => {
|
||||
loadError.value = "";
|
||||
try {
|
||||
await infoStore.createCharacter(props.alter);
|
||||
prepareHelperRoleImport();
|
||||
} catch (error) {
|
||||
loadError.value = error instanceof Error ? error.message : "角色数据加载失败";
|
||||
} finally {
|
||||
@@ -66,6 +117,103 @@ const switchTab = (tab: (typeof tabs)[number]["key"]) => {
|
||||
router.push(`/dcalc/character/${props.alter}/${tab}`);
|
||||
};
|
||||
|
||||
const resetImportMessage = () => {
|
||||
importStatus.value = "";
|
||||
importError.value = "";
|
||||
};
|
||||
|
||||
const applyHelperConfig = (payload: HelperConfigPayload) => {
|
||||
if (payload.equips) configStore.config.equips = payload.equips;
|
||||
if (payload.avatars || payload.avatar) {
|
||||
configStore.config.avatar = payload.avatars ?? payload.avatar ?? configStore.config.avatar;
|
||||
}
|
||||
if (payload.avatarLink !== undefined) configStore.config.avatarLink = payload.avatarLink;
|
||||
if (payload.emblems) configStore.config.emblems = payload.emblems;
|
||||
if (payload.fogOathLv !== undefined) configStore.config.sundry.fog = payload.fogOathLv;
|
||||
if (payload.oaths) configStore.config.oaths = payload.oaths;
|
||||
configStore.pushChangeSource("Import", "助手打造配置已导入");
|
||||
};
|
||||
|
||||
const importHelperConfig = async () => {
|
||||
resetImportMessage();
|
||||
const uid = helperUid.value.trim();
|
||||
if (!uid) {
|
||||
importError.value = "请输入助手社区 ID。";
|
||||
return;
|
||||
}
|
||||
|
||||
helperImportLoading.value = true;
|
||||
try {
|
||||
const payload = (await api.getConfigFromHelper(uid)) as HelperConfigPayload;
|
||||
applyHelperConfig(payload);
|
||||
helperImportOpen.value = false;
|
||||
helperUid.value = "";
|
||||
importStatus.value = "打造导入成功。";
|
||||
} catch (error) {
|
||||
importError.value = error instanceof Error ? error.message : "打造导入失败。";
|
||||
} finally {
|
||||
helperImportLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const importHelperRoleConfig = async () => {
|
||||
resetImportMessage();
|
||||
const uid = helperStore.helperInfo?.id;
|
||||
const roleId = helperRole.value?.roleId;
|
||||
if (!uid || !roleId) {
|
||||
importError.value = "未找到可导入的助手角色。";
|
||||
return;
|
||||
}
|
||||
|
||||
helperImportLoading.value = true;
|
||||
try {
|
||||
const payload = (await api.getConfigFromHelperAlter(uid, roleId)) as HelperConfigPayload;
|
||||
applyHelperConfig(payload);
|
||||
helperRoleImportOpen.value = false;
|
||||
importStatus.value = "助手角色打造导入成功。";
|
||||
} catch (error) {
|
||||
importError.value = error instanceof Error ? error.message : "助手角色打造导入失败。";
|
||||
} finally {
|
||||
helperImportLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const importSkillConfig = async () => {
|
||||
resetImportMessage();
|
||||
const code = skillCode.value.trim();
|
||||
if (!code) {
|
||||
importError.value = "请输入技能加点代码。";
|
||||
return;
|
||||
}
|
||||
|
||||
skillImportLoading.value = true;
|
||||
try {
|
||||
const payload = (await api.getSkillFromCode(code)) as SkillImportPayload;
|
||||
if (payload.skills) {
|
||||
configStore.config.skills = payload.skills;
|
||||
configStore.pushChangeSource("Import", "技能加点代码已导入");
|
||||
}
|
||||
skillImportOpen.value = false;
|
||||
skillCode.value = "";
|
||||
importStatus.value = "技能导入成功。";
|
||||
} catch (error) {
|
||||
importError.value = error instanceof Error ? error.message : "技能导入失败。";
|
||||
} finally {
|
||||
skillImportLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const prepareHelperRoleImport = () => {
|
||||
const roleId = route.query.roleId;
|
||||
if (typeof roleId !== "string") return;
|
||||
|
||||
const target = helperStore.helperInfo?.roleList.find((item) => item.roleId === roleId);
|
||||
if (!target) return;
|
||||
|
||||
helperRole.value = target;
|
||||
helperRoleImportOpen.value = true;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadCharacter();
|
||||
window.addEventListener("beforeunload", configStore.saveConfig);
|
||||
@@ -81,6 +229,13 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => route.query.roleId,
|
||||
() => {
|
||||
prepareHelperRoleImport();
|
||||
},
|
||||
);
|
||||
|
||||
watch(showGlobalResultPanel, (show) => {
|
||||
if (!show) {
|
||||
isResultSheetOpen.value = false;
|
||||
@@ -125,6 +280,79 @@ onUnmounted(() => {
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<Sheet v-model:open="helperImportOpen">
|
||||
<SheetTrigger as-child>
|
||||
<Button size="sm" variant="outline" @click="resetImportMessage">
|
||||
<FileInput class="size-4" />
|
||||
打造导入
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent class="w-full overflow-y-auto sm:max-w-md">
|
||||
<SheetHeader>
|
||||
<SheetTitle>打造导入</SheetTitle>
|
||||
<SheetDescription>助手社区 ID</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div class="grid gap-3 px-4">
|
||||
<Input v-model="helperUid" placeholder="社区 ID" @keyup.enter="importHelperConfig" />
|
||||
<p v-if="importError" class="text-sm text-destructive">{{ importError }}</p>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button :disabled="helperImportLoading" @click="importHelperConfig">
|
||||
{{ helperImportLoading ? "导入中..." : "导入" }}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<Sheet v-model:open="skillImportOpen">
|
||||
<SheetTrigger as-child>
|
||||
<Button size="sm" variant="outline" @click="resetImportMessage">
|
||||
<WandSparkles class="size-4" />
|
||||
技能导入
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent class="w-full overflow-y-auto sm:max-w-md">
|
||||
<SheetHeader>
|
||||
<SheetTitle>技能导入</SheetTitle>
|
||||
<SheetDescription>技能加点代码</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div class="grid gap-3 px-4">
|
||||
<Textarea v-model="skillCode" class="min-h-28" placeholder="技能代码" />
|
||||
<p v-if="importError" class="text-sm text-destructive">{{ importError }}</p>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button :disabled="skillImportLoading" @click="importSkillConfig">
|
||||
{{ skillImportLoading ? "导入中..." : "导入" }}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<p v-if="importStatus" class="text-xs text-muted-foreground">{{ importStatus }}</p>
|
||||
</div>
|
||||
|
||||
<Sheet v-model:open="helperRoleImportOpen">
|
||||
<SheetContent class="w-full overflow-y-auto sm:max-w-md">
|
||||
<SheetHeader>
|
||||
<SheetTitle>助手角色导入</SheetTitle>
|
||||
<SheetDescription>{{ helperRole?.roleName || "助手角色" }}</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div class="grid gap-2 px-4 text-sm">
|
||||
<div class="rounded-md border p-3">
|
||||
<div class="font-medium">{{ helperRole?.roleJob }}</div>
|
||||
<div class="text-muted-foreground">名望 {{ helperRole?.fame ?? "-" }}</div>
|
||||
</div>
|
||||
<p v-if="importError" class="text-sm text-destructive">{{ importError }}</p>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button :disabled="helperImportLoading" @click="importHelperRoleConfig">
|
||||
{{ helperImportLoading ? "导入中..." : "导入" }}
|
||||
</Button>
|
||||
</SheetFooter>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<div
|
||||
:class="[
|
||||
'grid min-h-0 flex-1 grid-cols-1 gap-4',
|
||||
|
||||
Reference in New Issue
Block a user