index.vue 6.0 KB

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