Files
workspace/code/fms/fms-vue/src/components/I18nNameModal.vue
T
2026-09-01 22:20:55 +08:00

111 lines
2.7 KiB
Vue

<script setup>
/**
* 多语言名称编辑弹窗(通用组件)。
* 用于编辑一个对象在不同语言下的名称,支持任意语言列表。
*
* 用法:
* <I18nNameModal
* :open="open"
* :languages="I18N_LANGUAGES"
* :model-value="{ 'zh-CN': '名称', 'en-US': 'Name' }"
* @update:model-value="(v) => writeBack(v)"
* @update:open="(v) => (open = v)"
* />
*/
import { ref, watch } from 'vue'
import { Modal, Button, Input } from '@/components/ui'
defineOptions({ inheritAttrs: false })
const props = defineProps({
/** 受控打开状态 */
open: { type: Boolean, default: false },
/** 弹窗标题 */
title: { type: String, default: '多语言名称' },
/** 语言列表 [{ code, name, default }] */
languages: { type: Array, default: () => [] },
/** 各语言值 { [code]: value } */
modelValue: { type: Object, default: () => ({}) },
/** 底部提示文字 */
hint: { type: String, default: '' },
})
const emit = defineEmits(['update:open', 'update:modelValue', 'confirm'])
/** 本地草稿:打开时快照,确定时提交 */
const draft = ref({})
watch(
() => props.open,
(open) => {
if (open) draft.value = { ...props.modelValue }
},
)
function onValueChange(lang, value) {
draft.value = { ...draft.value, [lang.code]: value }
}
function onOk() {
emit('update:modelValue', { ...draft.value })
emit('confirm', { ...draft.value })
emit('update:open', false)
}
function onCancel() {
emit('update:open', false)
}
</script>
<template>
<Modal :open="open" :title="title" :width="520" :mask-closable="false" @cancel="onCancel">
<div class="i18n-name-modal">
<div class="i18n-name-row" v-for="lang in languages" :key="lang.code">
<span class="i18n-name-row__label">{{ lang.name }}</span>
<Input
class="i18n-name-row__input"
:model-value="draft[lang.code] || ''"
:placeholder="`请输入${lang.name}名称`"
@update:model-value="(v) => onValueChange(lang, v)"
/>
</div>
<p v-if="hint" class="i18n-name-modal__hint">{{ hint }}</p>
</div>
<template #footer>
<Button type="outline" @click="onCancel">取消</Button>
<Button type="primary" @click="onOk">确定</Button>
</template>
</Modal>
</template>
<style scoped lang="scss">
.i18n-name-modal {
display: flex;
flex-direction: column;
gap: 10px;
}
.i18n-name-row {
display: flex;
align-items: center;
gap: 10px;
max-width: 480px;
}
.i18n-name-row__label {
flex-shrink: 0;
width: 80px;
font-size: 13px;
color: var(--fms-text-secondary);
}
.i18n-name-row__input {
flex: 1;
min-width: 0;
}
.i18n-name-modal__hint {
margin: 0;
font-size: 12px;
line-height: 1.7;
color: var(--fms-text-secondary);
}
</style>