index.vue 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <template>
  2. <div class="multi-lang-input">
  3. <el-input v-model="inputModelValue" :placeholder="`请输入 ${currentLangLabel}`" clearable @update:model-value="(val: string) => { emit('update:modelValue', val); }">
  4. <template #append>
  5. <el-button @click="openDialog" circle>
  6. <template #icon>
  7. <i class="iconfont icon-diqiu1"></i>
  8. </template>
  9. </el-button>
  10. </template>
  11. </el-input>
  12. <el-dialog v-model="dialogVisible" title="多语言设置" draggable :close-on-click-modal="false" width="600px">
  13. <el-form ref="ruleFormRef" label-width="auto">
  14. <el-row :gutter="35">
  15. <el-col v-for="lang in languages" :key="lang.code" :span="24" class="mb10">
  16. <el-form-item :label="lang.label">
  17. <el-input v-model="multiLangValue[lang.code]" :placeholder="`请输入: ${lang.label}`" clearable />
  18. </el-form-item>
  19. </el-col>
  20. </el-row>
  21. </el-form>
  22. <template #footer>
  23. <el-button @click="aiTranslation">AI翻译</el-button>
  24. <el-button @click="closeDialog">关闭</el-button>
  25. <el-button type="primary" @click="confirmDialog">确认修改</el-button>
  26. </template>
  27. </el-dialog>
  28. </div>
  29. </template>
  30. <script setup lang="ts">
  31. import { ref, computed, onMounted } from 'vue';
  32. import { useLangStore } from '/@/stores/useLangStore';
  33. import { Local } from '/@/utils/storage';
  34. import { getAPI } from '/@/utils/axios-utils';
  35. import { SysLangTextApi } from '/@/api-services/api';
  36. import { ElMessage } from 'element-plus';
  37. const emit = defineEmits<{ (e: 'update:modelValue', value: string): void; }>();
  38. const ruleFormRef = ref();
  39. const fetchMultiLang = async () => {
  40. const result = await getAPI(SysLangTextApi).apiSysLangTextListPost({ entityName: props.entityName, entityId: props.entityId, fieldName: props.fieldName, pageSize: 200 }).then(res => res.data.result)
  41. return result ?? [];
  42. };
  43. const inputModelValue = computed({
  44. get: () => props.modelValue,
  45. set: (val) => emit('update:modelValue', val),
  46. });
  47. const props = defineProps<{
  48. modelValue: string;
  49. entityName: string;
  50. entityId: number;
  51. fieldName: string;
  52. }>();
  53. // 全局语言
  54. const langStore = useLangStore();
  55. const languages = ref<any>([] as any);
  56. // 当前语言(可根据用户设置或浏览器设置)
  57. const currentLang = ref('zh-CN');
  58. const activeLang = ref('zh-CN');
  59. // 是否弹框
  60. const dialogVisible = ref(false);
  61. // 多语言对象
  62. const multiLangValue = ref<Record<string, string>>({});
  63. // 当前语言显示 Label
  64. const currentLangLabel = computed(() => {
  65. return (
  66. languages.value.find((l: { code: string; }) => l.code === currentLang.value)?.Label || currentLang.value
  67. );
  68. });
  69. // 初始化语言
  70. onMounted(async () => {
  71. if (langStore.languages.length === 0) {
  72. await langStore.loadLanguages();
  73. }
  74. const themeConfig = Local.get('themeConfig');
  75. const globalI18n = themeConfig?.globalI18n;
  76. if (globalI18n) {
  77. const matched = langStore.languages.find(l => l.code === globalI18n);
  78. const langCode = matched?.code || 'zh-CN';
  79. currentLang.value = langCode;
  80. activeLang.value = langCode;
  81. }
  82. languages.value = langStore.languages;
  83. if (languages.value.length > 0) {
  84. currentLang.value = languages.value[0].code;
  85. activeLang.value = languages.value[0].code;
  86. }
  87. });
  88. const aiTranslation = async () => {
  89. languages.value.forEach(async (element: { code: string; value: string | null; }) => {
  90. if (element.code == currentLang.value) {
  91. return;
  92. }
  93. multiLangValue.value[element.code] = '正在翻译...';
  94. try {
  95. const text = await getAPI(SysLangTextApi).apiSysLangTextAiTranslateTextPost({ originalText: props.modelValue, targetLang: element.value }).then(res => res.data.result);
  96. if (text) {
  97. multiLangValue.value[element.code] = text;
  98. } else {
  99. multiLangValue.value[element.code] = '';
  100. }
  101. } catch (e: any) {
  102. multiLangValue.value[element.code] = '';
  103. ElMessage.warning(e.message);
  104. }
  105. });
  106. }
  107. // 打开对话框(点击按钮)
  108. const openDialog = async () => {
  109. if (!props.entityId) {
  110. ElMessage.warning('请先保存数据!');
  111. return;
  112. }
  113. multiLangValue.value = {};
  114. const res = await fetchMultiLang();
  115. multiLangValue.value[currentLang.value] = props.modelValue;
  116. res.forEach((element: { langCode?: string | null; content?: string | null; }) => {
  117. multiLangValue.value[element.langCode ?? 0] = element.content ?? '';
  118. });
  119. dialogVisible.value = true;
  120. ruleFormRef.value?.resetFields();
  121. };
  122. // 关闭对话框(只是关闭)
  123. const closeDialog = () => {
  124. dialogVisible.value = false;
  125. multiLangValue.value = {};
  126. ruleFormRef.value?.resetFields();
  127. };
  128. // 确认按钮(更新 + 关闭)
  129. const confirmDialog = async () => {
  130. const langItems = Object.entries(multiLangValue.value)
  131. .filter(([_, content]) => content && content.trim() !== '')
  132. .map(([code, content]) => ({
  133. entityName: props.entityName,
  134. entityId: props.entityId,
  135. fieldName: props.fieldName,
  136. langCode: code,
  137. content: content,
  138. }));
  139. if (langItems.length === 0) {
  140. ElMessage.warning('请输入至少一条多语言内容!');
  141. return;
  142. }
  143. try {
  144. await getAPI(SysLangTextApi).apiSysLangTextBatchSavePost(langItems);
  145. ElMessage.success('保存成功!');
  146. // 同步当前语言内容到父组件 input
  147. emit('update:modelValue', multiLangValue.value[currentLang.value]);
  148. dialogVisible.value = false;
  149. } catch (err) {
  150. console.error(err);
  151. ElMessage.error('保存失败!');
  152. }
  153. dialogVisible.value = false;
  154. ruleFormRef.value?.resetFields();
  155. };
  156. </script>
  157. <style lang="scss" scoped>
  158. .multi-lang-input {
  159. width: 100%;
  160. }
  161. .mb10:last-child { margin-bottom: 0 !important; }
  162. </style>