fix: debug with type error checks

This commit is contained in:
pa
2025-07-16 14:23:06 +09:00
committed by Natsumi
parent 0e50a67c25
commit b23687430e
13 changed files with 217 additions and 194 deletions

View File

@@ -87,8 +87,7 @@ const worldReq = {
},
/**
* @param {{id: string}} params
* @returns {Promise<{json: any, params}>}
* @type {import('../types/api/world').SaveWorld}
*/
saveWorld(params) {
const worldStore = useWorldStore();

View File

@@ -60,7 +60,7 @@
}
if (Array.isArray(props.avatartags)) {
avatarTags.value = props.avatartags.map((tag) => tag.replace('content_', '')).join(', ');
avatarTags.value = props.avatartags.map((tag) => String(tag).replace('content_', '')).join(', ');
}
};

View File

@@ -86,7 +86,7 @@
capacity: 0,
queueSize: 0,
queueEnabled: false,
platforms: [],
platforms: {},
userList: [],
gameServerVersion: '',
canCloseInstance: false,

View File

@@ -48,32 +48,32 @@
<br />
<div
class="x-friend-item"
v-if="image.versions && image.versions.length > 0"
v-for="image in galleryTable"
:key="image.id"
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
@click="setProfilePicOverride(image.id)"
:class="{ 'current-vrcplus-icon': compareCurrentProfilePic(image.id) }">
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteGalleryImage(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button>
</div>
<template v-if="image.versions && image.versions.length > 0">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
@click="setProfilePicOverride(image.id)"
:class="{ 'current-vrcplus-icon': compareCurrentProfilePic(image.id) }">
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteGalleryImage(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button></div
></template>
</div>
</el-tab-pane>
@@ -117,32 +117,32 @@
<br />
<div
class="x-friend-item"
v-if="image.versions && image.versions.length > 0"
v-for="image in VRCPlusIconsTable"
:key="image.id"
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
@click="setVRCPlusIcon(image.id)"
:class="{ 'current-vrcplus-icon': compareCurrentVRCPlusIcon(image.id) }">
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteVRCPlusIcon(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button>
</div>
<template v-if="image.versions && image.versions.length > 0"
><div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
@click="setVRCPlusIcon(image.id)"
:class="{ 'current-vrcplus-icon': compareCurrentVRCPlusIcon(image.id) }">
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteVRCPlusIcon(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button></div
></template>
</div>
</el-tab-pane>
@@ -226,65 +226,67 @@
<br />
<div
class="x-friend-item"
v-if="image.versions && image.versions.length > 0"
v-for="image in emojiTable"
:key="image.id"
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
style="overflow: hidden"
@click="
showFullscreenImageDialog(
image.versions[image.versions.length - 1].file.url,
getEmojiFileName(image)
)
">
<template v-if="image.frames">
<div
class="avatar"
:style="
generateEmojiStyle(
image.versions[image.versions.length - 1].file.url,
image.framesOverTime,
image.frames,
image.loopStyle
)
"></div>
</template>
<template v-else>
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</template>
</div>
<div style="display: inline-block; margin: 5px">
<span v-if="image.loopStyle === 'pingpong'">
<i class="el-icon-refresh el-icon--left"></i>
</span>
<span style="margin-right: 5px">{{ image.animationStyle }}</span>
<span v-if="image.framesOverTime" style="margin-right: 5px">{{ image.framesOverTime }}fps</span>
<span v-if="image.frames" style="margin-right: 5px">{{ image.frames }}frames</span>
<br />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
<template v-if="image.versions && image.versions.length > 0">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
style="overflow: hidden"
@click="
showFullscreenImageDialog(
image.versions[image.versions.length - 1].file.url,
getEmojiFileName(image)
)
"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteEmoji(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button>
</div>
">
<template v-if="image.frames">
<div
class="avatar"
:style="
generateEmojiStyle(
image.versions[image.versions.length - 1].file.url,
image.framesOverTime,
image.frames,
image.loopStyle
)
"></div>
</template>
<template v-else>
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</template>
</div>
<div style="display: inline-block; margin: 5px">
<span v-if="image.loopStyle === 'pingpong'">
<i class="el-icon-refresh el-icon--left"></i>
</span>
<span style="margin-right: 5px">{{ image.animationStyle }}</span>
<span v-if="image.framesOverTime" style="margin-right: 5px"
>{{ image.framesOverTime }}fps</span
>
<span v-if="image.frames" style="margin-right: 5px">{{ image.frames }}frames</span>
<br />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="
showFullscreenImageDialog(
image.versions[image.versions.length - 1].file.url,
getEmojiFileName(image)
)
"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteEmoji(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button></div
></template>
</div>
</el-tab-pane>
@@ -320,32 +322,32 @@
<br />
<div
class="x-friend-item"
v-if="image.versions && image.versions.length > 0"
v-for="image in stickerTable"
:key="image.id"
style="display: inline-block; margin-top: 10px; width: unset; cursor: default">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
style="overflow: hidden"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)">
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteSticker(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button>
</div>
<template v-if="image.versions && image.versions.length > 0">
<div
class="vrcplus-icon"
v-if="image.versions[image.versions.length - 1].file.url"
style="overflow: hidden"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)">
<img class="avatar" v-lazy="image.versions[image.versions.length - 1].file.url" />
</div>
<div style="float: right; margin-top: 5px">
<el-button
type="default"
@click="showFullscreenImageDialog(image.versions[image.versions.length - 1].file.url)"
size="mini"
icon="el-icon-picture-outline"
circle></el-button>
<el-button
type="default"
@click="deleteSticker(image.id)"
size="mini"
icon="el-icon-delete"
circle
style="margin-left: 5px"></el-button></div
></template>
</div>
</el-tab-pane>

View File

@@ -79,7 +79,7 @@
</template>
<script setup>
import { ref, computed, nextTick, watch, getCurrentInstance, onMounted } from 'vue';
import { ref, computed, nextTick, watch, getCurrentInstance } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n-bridge';
import { instanceRequest, worldRequest } from '../../api';

View File

@@ -101,23 +101,25 @@
<el-option-group :label="t('dialog.new_instance.group_placeholder')">
<el-option
v-for="group in currentUserGroups.values()"
v-if="
group &&
(hasGroupPermission(group, 'group-instance-public-create') ||
hasGroupPermission(group, 'group-instance-plus-create') ||
hasGroupPermission(group, 'group-instance-open-create'))
"
:key="group.id"
:label="group.name"
:value="group.id"
class="x-friend-item"
style="height: auto; width: 478px">
<div class="avatar">
<img v-lazy="group.iconUrl" />
</div>
<div class="detail">
<span class="name" v-text="group.name"></span>
</div>
<template
v-if="
group &&
(hasGroupPermission(group, 'group-instance-public-create') ||
hasGroupPermission(group, 'group-instance-plus-create') ||
hasGroupPermission(group, 'group-instance-open-create'))
">
<div class="avatar">
<img v-lazy="group.iconUrl" />
</div>
<div class="detail">
<span class="name" v-text="group.name"></span>
</div>
</template>
</el-option>
</el-option-group>
</el-select>
@@ -362,18 +364,18 @@
<el-option-group :label="t('dialog.new_instance.group_placeholder')">
<el-option
v-for="group in currentUserGroups.values()"
v-if="group"
:key="group.id"
class="x-friend-item"
:label="group.name"
:value="group.id"
style="height: auto; width: 478px">
<div class="avatar">
<img v-lazy="group.iconUrl" />
</div>
<div class="detail">
<span class="name" v-text="group.name"></span>
</div>
<template v-if="group">
<div class="avatar">
<img v-lazy="group.iconUrl" />
</div>
<div class="detail">
<span class="name" v-text="group.name"></span></div
></template>
</el-option>
</el-option-group>
</el-select>

View File

@@ -7,12 +7,13 @@
append-to-body
@close="closeDialog">
<div>
<div
v-for="image in previousImagesTable"
v-if="image.file"
:key="image.version"
style="display: inline-block">
<el-popover class="x-change-image-item" placement="right" width="500px" trigger="click">
<div v-for="image in previousImagesTable" :key="image.version" style="display: inline-block">
<el-popover
class="x-change-image-item"
placement="right"
width="500px"
trigger="click"
v-if="image.file">
<img slot="reference" v-lazy="image.file.url" class="x-link" />
<img
v-lazy="image.file.url"

View File

@@ -44,7 +44,7 @@
{{ t('dialog.vrcx_updater.cancel') }}
</el-button>
<el-button
v-if="VRCXUpdateDialog.release !== pendingVRCXInstall"
v-if="Boolean(VRCXUpdateDialog.release) !== pendingVRCXInstall"
:disabled="updateInProgress"
type="primary"
size="small"

View File

@@ -77,7 +77,8 @@
base64SignatureFile: '',
signatureMd5: '',
fileId: '',
avatarId: ''
avatarId: '',
worldId: ''
});
function uploadWorldImage() {
@@ -114,8 +115,9 @@
function onFileChangeWorldImage(e) {
const clearFile = function () {
if (document.querySelector('#WorldImageUploadButton')) {
document.querySelector('#WorldImageUploadButton').value = '';
const fileInput = /** @type {HTMLInputElement} */ (document.querySelector('#WorldImageUploadButton'));
if (fileInput) {
fileInput.value = '';
}
};
const files = e.target.files || e.dataTransfer.files;
@@ -144,10 +146,10 @@
const r = new FileReader();
r.onload = async function (file) {
try {
const base64File = await resizeImageToFitLimits(btoa(r.result));
const base64File = await resizeImageToFitLimits(btoa(r.result.toString()));
// 10MB
const fileMd5 = await genMd5(base64File);
const fileSizeInBytes = parseInt(file.total, 10);
const fileSizeInBytes = parseInt(file.total.toString(), 10);
const base64SignatureFile = await genSig(base64File);
const signatureMd5 = await genMd5(base64SignatureFile);
const signatureSizeInBytes = parseInt(await genLength(base64SignatureFile), 10);
@@ -168,7 +170,8 @@
base64SignatureFile,
signatureMd5,
fileId,
worldId
worldId,
...worldImage.value
};
const params = {
fileMd5,
@@ -231,7 +234,7 @@
if (json.status !== 200) {
changeWorldImageDialogLoading.value = false;
$throw('World image upload failed', json, params.url);
$throw(json.status, 'World image upload failed', params.url);
}
const args = {
json,
@@ -284,7 +287,7 @@
if (json.status !== 200) {
changeWorldImageDialogLoading.value = false;
$throw('World image upload failed', json, params.url);
$throw(json.status, 'World image upload failed', params.url);
}
const args = {
json,

View File

@@ -73,7 +73,7 @@
</el-checkbox>
<template #footer>
<div style="display: flex">
<el-button size="small" @click="setWorldTagsDialog.visible = false">
<el-button size="small" @click="isVisible = false">
{{ t('dialog.set_world_tags.cancel') }}
</el-button>
<el-button type="primary" size="small" @click="saveSetWorldTagsDialog">
@@ -168,13 +168,13 @@
const authorTags = [];
const contentTags = [];
props.oldTags.forEach((tag) => {
if (tag.startsWith('author_tag_')) {
authorTags.unshift(tag.substring(11));
if (String(tag).startsWith('author_tag_')) {
authorTags.unshift(String(tag).substring(11));
}
if (tag.startsWith('content_')) {
contentTags.unshift(tag.substring(8));
if (String(tag).startsWith('content_')) {
contentTags.unshift(String(tag).substring(8));
}
switch (tag) {
switch (String(tag)) {
case 'content_horror':
D.contentHorror = true;
break;

View File

@@ -723,10 +723,10 @@
style="margin-left: 5px"
@click="downloadAndSaveJson(worldDialog.id, worldDialog.ref)"></el-button>
<el-tree :data="treeData" style="margin-top: 5px; font-size: 12px">
<template slot-scope="scope">
<template #default="{ data }">
<span>
<span style="font-weight: bold; margin-right: 5px" v-text="scope.data.key"></span>
<span v-if="!scope.data.children" v-text="scope.data.value"></span>
<span style="font-weight: bold; margin-right: 5px" v-text="data.key"></span>
<span v-if="!data.children" v-text="data.value"></span>
</span>
</template>
</el-tree>
@@ -856,7 +856,8 @@
const timeInLab = computed(() => {
return timeToText(
new Date(worldDialog.value.ref.publicationDate) - new Date(worldDialog.value.ref.labsPublicationDate)
new Date(worldDialog.value.ref.publicationDate).getTime() -
new Date(worldDialog.value.ref.labsPublicationDate).getTime()
);
});
@@ -1194,7 +1195,7 @@
worldRequest
.saveWorld({
id: world.id,
capacity: instance.inputValue
capacity: Number(instance.inputValue)
})
.then((args) => {
proxy.$message({
@@ -1224,7 +1225,7 @@
worldRequest
.saveWorld({
id: world.id,
recommendedCapacity: instance.inputValue
recommendedCapacity: Number(instance.inputValue)
})
.then((args) => {
proxy.$message({

View File

@@ -46,6 +46,27 @@ export type GetWorlds = (
option?: string;
}>;
export type SaveWorld = (params: {
id: string;
name?: string;
description?: string;
capacity?: number;
recommendedCapacity?: number;
previewYoutubeId?: string;
urlList?: string[];
tags?: string[];
}) => Promise<{
json: SaveWorldResponse;
params: {
id: string;
name?: string;
description?: string;
capacity?: number;
recommendedCapacity?: number;
previewYoutubeId?: string;
};
}>;
// Type aliases
type WorldSearchResponse = WorldSearchResponseItem[];
@@ -67,3 +88,20 @@ interface GetWorldResponse extends BaseWorld {
version: number;
visits: number;
}
interface SaveWorldResponse extends BaseWorld {
description: string;
featured: boolean;
pendingUpload: boolean;
tags: string[];
thumbnailImageUrl: string;
imageUrl: string;
name: string;
authorId: string;
authorName: string;
id: string;
updated_at: string;
urlList: string[];
version: number;
visits: number;
}

View File

@@ -398,29 +398,6 @@ declare global {
data?: any;
}): Promise<{ status: number; data: string }>;
};
const electron: {
openFileDialog: () => Promise<string>;
openDirectoryDialog: () => Promise<string>;
desktopNotification: (
displayName: string,
body?: string,
image?: string
) => Promise<void>;
onWindowPositionChanged: (
Function: (event: any, position: { x: number; y: number }) => void
) => void;
onWindowSizeChanged: (
Function: (
event: any,
size: { width: number; height: number }
) => void
) => void;
onWindowStateChange: (
Function: (event: any, state: { windowState: any }) => void
) => void;
restartApp: () => Promise<void>;
};
}
export {};