refactor: Organize Project Structure (#1211)

* refactor: Organize Project Structure

* fix

* fix

* rm security

* fix
This commit is contained in:
pa
2025-04-18 15:04:03 +09:00
committed by GitHub
parent 59d3ead781
commit 6bda44be52
106 changed files with 172 additions and 165 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,130 @@
<template>
<el-dialog
ref="setAvatarStylesDialog"
class="x-dialog"
:before-close="beforeDialogClose"
:visible.sync="setAvatarStylesDialog.visible"
:title="t('dialog.set_avatar_styles.header')"
width="400px"
append-to-body
@mousedown.native="dialogMouseDown"
@mouseup.native="dialogMouseUp">
<template v-if="setAvatarStylesDialog.visible">
<div>
<span>{{ t('dialog.set_avatar_styles.primary_style') }}</span>
<el-select
v-model="setAvatarStylesDialog.primaryStyle"
:placeholder="t('dialog.set_avatar_styles.select_style')"
size="small"
clearable
style="display: inline-block">
<el-option
v-for="(style, index) in setAvatarStylesDialog.availableAvatarStyles"
:key="index"
:label="style"
:value="style"></el-option>
</el-select>
</div>
<br />
<div>
<span>{{ t('dialog.set_avatar_styles.secondary_style') }}</span>
<el-select
v-model="setAvatarStylesDialog.secondaryStyle"
:placeholder="t('dialog.set_avatar_styles.select_style')"
size="small"
clearable
style="display: inline-block">
<el-option
v-for="(style, index) in setAvatarStylesDialog.availableAvatarStyles"
:key="index"
:label="style"
:value="style"></el-option>
</el-select>
</div>
</template>
<template #footer>
<el-button size="small" @click="setAvatarStylesDialog.visible = false">{{
t('dialog.set_avatar_styles.cancel')
}}</el-button>
<el-button type="primary" size="small" @click="saveSetAvatarStylesDialog">{{
t('dialog.set_avatar_styles.save')
}}</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { inject, watch, getCurrentInstance } from 'vue';
import { useI18n } from 'vue-i18n-bridge';
import { avatarRequest } from '../../../api';
const beforeDialogClose = inject('beforeDialogClose');
const dialogMouseDown = inject('dialogMouseDown');
const dialogMouseUp = inject('dialogMouseUp');
const { t } = useI18n();
const instance = getCurrentInstance();
const $message = instance.proxy.$message;
const props = defineProps({
setAvatarStylesDialog: {
type: Object,
required: true
}
});
watch(
() => props.setAvatarStylesDialog.visible,
(newVal) => {
if (newVal) {
getAvatarStyles();
}
}
);
async function getAvatarStyles() {
const ref = await avatarRequest.getAvailableAvatarStyles();
const styles = [];
const stylesMap = new Map();
for (const style of ref.json) {
styles.push(style.styleName);
stylesMap.set(style.styleName, style.id);
}
props.setAvatarStylesDialog.availableAvatarStyles = styles;
props.setAvatarStylesDialog.availableAvatarStylesMap = stylesMap;
}
function saveSetAvatarStylesDialog() {
if (
props.setAvatarStylesDialog.initialPrimaryStyle === props.setAvatarStylesDialog.primaryStyle &&
props.setAvatarStylesDialog.initialSecondaryStyle === props.setAvatarStylesDialog.secondaryStyle
) {
props.setAvatarStylesDialog.visible = false;
return;
}
const primaryStyleId =
props.setAvatarStylesDialog.availableAvatarStylesMap.get(props.setAvatarStylesDialog.primaryStyle) || '';
const secondaryStyleId =
props.setAvatarStylesDialog.availableAvatarStylesMap.get(props.setAvatarStylesDialog.secondaryStyle) || '';
const params = {
id: props.setAvatarStylesDialog.avatarId,
primaryStyle: primaryStyleId,
secondaryStyle: secondaryStyleId
};
avatarRequest
.saveAvatar(params)
.then(() => {
$message.success(t('dialog.set_avatar_styles.save_success'));
props.setAvatarStylesDialog.visible = false;
})
.catch((error) => {
$message.error(t('dialog.set_avatar_styles.save_failed'));
console.error('Error saving avatar styles:', error);
});
}
</script>
<style scoped></style>

View File

@@ -0,0 +1,289 @@
<template>
<el-dialog
ref="setAvatarTagsDialog"
class="x-dialog"
:before-close="beforeDialogClose"
:visible.sync="setAvatarTagsDialog.visible"
:title="t('dialog.set_avatar_tags.header')"
width="770px"
append-to-body
@mousedown.native="dialogMouseDown"
@mouseup.native="dialogMouseUp">
<template v-if="setAvatarTagsDialog.visible">
<el-checkbox v-model="setAvatarTagsDialog.contentHorror" @change="updateSelectedAvatarTags">{{
t('dialog.set_avatar_tags.content_horror')
}}</el-checkbox>
<br />
<el-checkbox v-model="setAvatarTagsDialog.contentGore" @change="updateSelectedAvatarTags">{{
t('dialog.set_avatar_tags.content_gore')
}}</el-checkbox>
<br />
<el-checkbox v-model="setAvatarTagsDialog.contentViolence" @change="updateSelectedAvatarTags">{{
t('dialog.set_avatar_tags.content_violence')
}}</el-checkbox>
<br />
<el-checkbox v-model="setAvatarTagsDialog.contentAdult" @change="updateSelectedAvatarTags">{{
t('dialog.set_avatar_tags.content_adult')
}}</el-checkbox>
<br />
<el-checkbox v-model="setAvatarTagsDialog.contentSex" @change="updateSelectedAvatarTags">{{
t('dialog.set_avatar_tags.content_sex')
}}</el-checkbox>
<br />
<el-input
v-model="setAvatarTagsDialog.selectedTagsCsv"
size="mini"
:autosize="{ minRows: 2, maxRows: 5 }"
:placeholder="t('dialog.set_avatar_tags.custom_tags_placeholder')"
style="margin-top: 10px"
@input="updateInputAvatarTags"></el-input>
<template v-if="setAvatarTagsDialog.ownAvatars.length === setAvatarTagsDialog.selectedCount">
<el-button size="small" @click="setAvatarTagsSelectToggle">{{
t('dialog.set_avatar_tags.select_none')
}}</el-button>
</template>
<template v-else>
<el-button size="small" @click="setAvatarTagsSelectToggle">{{
t('dialog.set_avatar_tags.select_all')
}}</el-button>
</template>
<span style="margin-left: 5px"
>{{ setAvatarTagsDialog.selectedCount }} / {{ setAvatarTagsDialog.ownAvatars.length }}</span
>
<span v-if="setAvatarTagsDialog.loading" style="margin-left: 5px">
<i class="el-icon-loading"></i>
</span>
<br />
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px; max-height: 280px">
<div
v-for="avatar in setAvatarTagsDialog.ownAvatars"
:key="avatar.id"
class="x-friend-item x-friend-item-border"
style="width: 350px"
@click="showAvatarDialog(avatar.id)">
<div class="avatar">
<img v-if="avatar.thumbnailImageUrl" v-lazy="avatar.thumbnailImageUrl" />
</div>
<div class="detail">
<span class="name" v-text="avatar.name"></span>
<span
v-if="avatar.releaseStatus === 'public'"
class="extra"
style="color: #67c23a"
v-text="avatar.releaseStatus"></span>
<span
v-else-if="avatar.releaseStatus === 'private'"
class="extra"
style="color: #f56c6c"
v-text="avatar.releaseStatus"></span>
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
<span class="extra" v-text="avatar.$tagString"></span>
</div>
<el-button type="text" size="mini" style="margin-left: 5px" @click.stop>
<el-checkbox v-model="avatar.$selected" @change="updateAvatarTagsSelection"></el-checkbox>
</el-button>
</div>
</div>
</template>
<template #footer>
<el-button size="small" @click="setAvatarTagsDialog.visible = false">{{
t('dialog.set_avatar_tags.cancel')
}}</el-button>
<el-button type="primary" size="small" @click="saveSetAvatarTagsDialog">{{
t('dialog.set_avatar_tags.save')
}}</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { inject, watch, getCurrentInstance } from 'vue';
import { useI18n } from 'vue-i18n-bridge';
import { avatarRequest } from '../../../api';
const beforeDialogClose = inject('beforeDialogClose');
const dialogMouseDown = inject('dialogMouseDown');
const dialogMouseUp = inject('dialogMouseUp');
const showAvatarDialog = inject('showAvatarDialog');
const { t } = useI18n();
const instance = getCurrentInstance();
const $message = instance.proxy.$message;
const props = defineProps({
setAvatarTagsDialog: {
type: Object,
required: true
}
});
watch(
() => props.setAvatarTagsDialog.visible,
(newVal) => {
if (newVal) {
updateAvatarTagsSelection();
updateSelectedAvatarTags();
}
}
);
function updateSelectedAvatarTags() {
const D = props.setAvatarTagsDialog;
if (D.contentHorror) {
if (!D.selectedTags.includes('content_horror')) {
D.selectedTags.push('content_horror');
}
} else if (D.selectedTags.includes('content_horror')) {
D.selectedTags.splice(D.selectedTags.indexOf('content_horror'), 1);
}
if (D.contentGore) {
if (!D.selectedTags.includes('content_gore')) {
D.selectedTags.push('content_gore');
}
} else if (D.selectedTags.includes('content_gore')) {
D.selectedTags.splice(D.selectedTags.indexOf('content_gore'), 1);
}
if (D.contentViolence) {
if (!D.selectedTags.includes('content_violence')) {
D.selectedTags.push('content_violence');
}
} else if (D.selectedTags.includes('content_violence')) {
D.selectedTags.splice(D.selectedTags.indexOf('content_violence'), 1);
}
if (D.contentAdult) {
if (!D.selectedTags.includes('content_adult')) {
D.selectedTags.push('content_adult');
}
} else if (D.selectedTags.includes('content_adult')) {
D.selectedTags.splice(D.selectedTags.indexOf('content_adult'), 1);
}
if (D.contentSex) {
if (!D.selectedTags.includes('content_sex')) {
D.selectedTags.push('content_sex');
}
} else if (D.selectedTags.includes('content_sex')) {
D.selectedTags.splice(D.selectedTags.indexOf('content_sex'), 1);
}
D.selectedTagsCsv = D.selectedTags.join(',').replace(/content_/g, '');
}
function updateAvatarTagsSelection() {
const D = props.setAvatarTagsDialog;
D.selectedCount = 0;
for (const ref of D.ownAvatars) {
if (ref.$selected) {
D.selectedCount++;
}
ref.$tagString = '';
const contentTags = [];
ref.tags.forEach((tag) => {
if (tag.startsWith('content_')) {
contentTags.push(tag.substring(8));
}
});
for (let i = 0; i < contentTags.length; ++i) {
const tag = contentTags[i];
if (i < contentTags.length - 1) {
ref.$tagString += `${tag}, `;
} else {
ref.$tagString += tag;
}
}
}
// props.setAvatarTagsDialog.forceUpdate++;
}
function setAvatarTagsSelectToggle() {
const D = props.setAvatarTagsDialog;
const allSelected = D.ownAvatars.length === D.selectedCount;
for (const ref of D.ownAvatars) {
ref.$selected = !allSelected;
}
updateAvatarTagsSelection();
}
async function saveSetAvatarTagsDialog() {
const D = props.setAvatarTagsDialog;
if (D.loading) {
return;
}
D.loading = true;
try {
for (let i = D.ownAvatars.length - 1; i >= 0; --i) {
const ref = D.ownAvatars[i];
if (!D.visible) {
break;
}
if (!ref.$selected) {
continue;
}
const tags = [...D.selectedTags];
for (const tag of ref.tags) {
if (!tag.startsWith('content_')) {
tags.push(tag);
}
}
await avatarRequest.saveAvatar({
id: ref.id,
tags
});
D.selectedCount--;
}
} catch (err) {
console.error(err);
$message({
message: 'Error saving avatar tags',
type: 'error'
});
} finally {
D.loading = false;
D.visible = false;
}
}
function updateInputAvatarTags() {
const D = props.setAvatarTagsDialog;
D.contentHorror = false;
D.contentGore = false;
D.contentViolence = false;
D.contentAdult = false;
D.contentSex = false;
const tags = D.selectedTagsCsv.split(',');
D.selectedTags = [];
for (const tag of tags) {
switch (tag) {
case 'horror':
D.contentHorror = true;
break;
case 'gore':
D.contentGore = true;
break;
case 'violence':
D.contentViolence = true;
break;
case 'adult':
D.contentAdult = true;
break;
case 'sex':
D.contentSex = true;
break;
}
if (!D.selectedTags.includes(`content_${tag}`)) {
D.selectedTags.push(`content_${tag}`);
}
}
}
// useless
// $app.data.avatarContentTags = [
// 'content_horror',
// 'content_gore',
// 'content_violence',
// 'content_adult',
// 'content_sex'
// ];
</script>
<style scoped></style>