TranslateDialog.vue 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <template>
  2. <el-dialog
  3. :title="titleText"
  4. :visible.sync="visible"
  5. width="600px"
  6. :close-on-click-modal="false"
  7. @close="dialogClose()"
  8. >
  9. <div class="translate-container">
  10. <div class="translate-section">
  11. <div class="section-label">原文:</div>
  12. <div class="text-content original-text">{{ initText }}</div>
  13. </div>
  14. <div class="translate-section lang-selector">
  15. <span class="section-label">目标语种:</span>
  16. <el-select v-model="lang" placeholder="请选择语言" size="mini" class="lang-select" @change="handleLangChange">
  17. <el-option v-for="item in langList" :key="item.type" :label="item.name" :value="item.type" />
  18. </el-select>
  19. </div>
  20. <div class="translate-section">
  21. <div class="section-label">译文:</div>
  22. <div class="text-content translated-text" :style="{ lineHeight: lang === 'ZH' ? '1' : '1.5' }">
  23. {{ translateResultText }}
  24. </div>
  25. </div>
  26. </div>
  27. <div slot="footer" class="dialog-footer">
  28. <el-button @click="dialogClose">关闭</el-button>
  29. </div>
  30. </el-dialog>
  31. </template>
  32. <script>
  33. import { GetLanguageTypeList, Texttrans } from '@/api/book';
  34. export default {
  35. name: 'TranslateDialog',
  36. components: {},
  37. props: {
  38. open: {
  39. type: Boolean,
  40. default: false,
  41. required: true,
  42. },
  43. initText: {
  44. type: String,
  45. default: '',
  46. },
  47. titleText: {
  48. type: String,
  49. default: '翻译',
  50. },
  51. bookId: {
  52. type: String,
  53. default: '',
  54. },
  55. },
  56. data() {
  57. return {
  58. visible: false,
  59. lang: 'ZH',
  60. langList: [],
  61. translateResultList: [],
  62. };
  63. },
  64. computed: {
  65. // 计算最终显示的译文字符串
  66. translateResultText() {
  67. if (!this.translateResultList || this.translateResultList.length === 0) {
  68. return '';
  69. }
  70. let resultText = this.translateResultList.map((item) => item.dst);
  71. return resultText.join('\n');
  72. },
  73. },
  74. watch: {
  75. open(newVal) {
  76. this.visible = newVal;
  77. if (newVal) {
  78. this.getLangList();
  79. this.translateResultList = [];
  80. }
  81. },
  82. visible(newVal) {
  83. if (!newVal) {
  84. this.$emit('update:open', false);
  85. this.translateResultList = [];
  86. this.lang = 'ZH';
  87. }
  88. },
  89. langList(newVal) {
  90. if (newVal && newVal.length > 0 && this.initText) {
  91. this.$nextTick(() => {
  92. this.fetchTranslation();
  93. });
  94. }
  95. },
  96. },
  97. methods: {
  98. dialogClose() {
  99. this.visible = false;
  100. },
  101. /**
  102. * 获取语言列表
  103. */
  104. getLangList() {
  105. if (!this.bookId) return;
  106. GetLanguageTypeList({ book_id: this.bookId, is_contain_zh: 'true' }).then(({ language_type_list }) => {
  107. this.langList = language_type_list;
  108. });
  109. },
  110. /**
  111. * 语种改变时触发
  112. */
  113. handleLangChange(val) {
  114. if (!this.initText) {
  115. this.$message.warning('暂无可翻译内容');
  116. return;
  117. }
  118. this.fetchTranslation();
  119. },
  120. /**
  121. * 调用翻译接口
  122. */
  123. fetchTranslation() {
  124. this.translateResultList = [];
  125. const params = {
  126. text: this.initText,
  127. from: 'zh',
  128. to: this.lang,
  129. };
  130. Texttrans(params)
  131. .then((res) => {
  132. if (res.status === 1) {
  133. this.translateResultList = res.trans_list || [];
  134. }
  135. })
  136. .catch(() => {
  137. this.$message.error('翻译失败');
  138. });
  139. },
  140. },
  141. };
  142. </script>
  143. <style lang="scss" scoped>
  144. .translate-container {
  145. padding: 10px;
  146. .translate-section {
  147. margin-bottom: 15px;
  148. .section-label {
  149. display: block;
  150. margin-bottom: 8px;
  151. font-size: 14px;
  152. font-weight: bold;
  153. color: #606266;
  154. }
  155. // 核心样式:保留换行符,自动换行
  156. .text-content {
  157. min-height: 40px;
  158. max-height: 300px;
  159. padding: 10px;
  160. overflow-y: auto;
  161. font-size: 14px;
  162. line-height: 1;
  163. color: #303133;
  164. word-break: break-all;
  165. white-space: pre-wrap;
  166. /* 关键:保留空格和换行符 */
  167. background-color: #f5f7fa;
  168. border: 1px solid #e4e7ed;
  169. border-radius: 4px;
  170. }
  171. .translated-text {
  172. line-height: 1.5;
  173. }
  174. &.lang-selector {
  175. display: flex;
  176. align-items: center;
  177. .section-label {
  178. margin-right: 10px;
  179. margin-bottom: 0;
  180. }
  181. }
  182. }
  183. }
  184. .el-dialog {
  185. :deep &__body {
  186. display: flex;
  187. flex-direction: column;
  188. row-gap: 8px;
  189. padding: 10px;
  190. .el-textarea__inner {
  191. height: 108px;
  192. }
  193. }
  194. }
  195. </style>