ttsModel.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <template>
  2. <n-modal v-model:show="showModal" :on-update:show="handleShow">
  3. <n-card
  4. style="width: 800px"
  5. title="文字转语音"
  6. :bordered="false"
  7. size="huge"
  8. role="dialog"
  9. transform-origin="center"
  10. aria-modal="true"
  11. >
  12. <template #header-extra>
  13. <n-icon size="30" @click="emits('close')" class="close-icon">
  14. <svg
  15. xmlns="http://www.w3.org/2000/svg"
  16. xmlns:xlink="http://www.w3.org/1999/xlink"
  17. viewBox="0 0 512 512"
  18. >
  19. <path
  20. d="M289.94 256l95-95A24 24 0 0 0 351 127l-95 95l-95-95a24 24 0 0 0-34 34l95 95l-95 95a24 24 0 1 0 34 34l95-95l95 95a24 24 0 0 0 34-34z"
  21. fill="currentColor"
  22. ></path>
  23. </svg>
  24. </n-icon>
  25. </template>
  26. <n-flex>
  27. <n-flex style="flex: 1">
  28. <n-input
  29. v-model:value="form.document"
  30. type="textarea"
  31. maxlength="500"
  32. show-count
  33. clearable
  34. placeholder="请输入"
  35. style="flex: 1; min-height: 300px"
  36. />
  37. </n-flex>
  38. <n-flex style="flex: 1" vertical>
  39. <div>选择人物</div>
  40. <n-flex class="card-select mb-5" justify="center">
  41. <template v-for="(card, index) in cardList" :key="index">
  42. <n-card
  43. style="flex: 1 1 48%"
  44. class="card-item"
  45. :class="{ active: activeType(card.type) }"
  46. @click="handleCharterSelect(card)"
  47. >
  48. <n-flex style="flex: 1">
  49. <n-avatar
  50. round
  51. size="small"
  52. src="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
  53. />
  54. <n-flex style="flex: 1" vertical>
  55. <span> {{ card.name }}</span>
  56. <span> {{ card.desc }}</span>
  57. </n-flex>
  58. </n-flex>
  59. </n-card>
  60. </template>
  61. </n-flex>
  62. <n-form
  63. ref="formRef"
  64. :model="form"
  65. label-placement="left"
  66. label-width="auto"
  67. require-mark-placement="right-hanging"
  68. :style="{
  69. maxWidth: '640px'
  70. }"
  71. >
  72. <n-form-item label="名称" path="inputValue">
  73. <n-input v-model:value="form.name" />
  74. </n-form-item>
  75. <n-form-item label="语速" path="inputValue">
  76. <n-slider
  77. v-model:value="form.speed"
  78. :step="0.1"
  79. :min="0.6"
  80. :max="2.5"
  81. />
  82. </n-form-item>
  83. <n-form-item label="音量" path="inputValue">
  84. <n-slider
  85. v-model:value="form.volume"
  86. :step="1"
  87. :min="-10"
  88. :max="10"
  89. />
  90. </n-form-item>
  91. </n-form>
  92. <!-- <n-slider v-model:value="form.speed" :step="1" />-->
  93. <!-- <n-slider v-model:value="form.volume" :step="1" />-->
  94. </n-flex>
  95. </n-flex>
  96. <template #footer>
  97. <n-flex justify="end">
  98. <n-button type="primary" @click="handleSave">保存</n-button>
  99. </n-flex>
  100. </template>
  101. </n-card>
  102. </n-modal>
  103. </template>
  104. <script setup lang="ts">
  105. import { ref, reactive, watchEffect, computed } from 'vue'
  106. import { NSlider, NForm, NFormItem, NAvatar, useMessage } from 'naive-ui'
  107. import { saveTOTTS, SaveTOTTSParams } from '@/api'
  108. import { useMainStore } from '@/store'
  109. const main = useMainStore()
  110. const showModal = ref(false)
  111. const formId = ref()
  112. const form = reactive({
  113. document: '',
  114. name: '',
  115. voiceType: 0,
  116. speed: 1,
  117. volume: 5
  118. })
  119. const message = useMessage()
  120. const emits = defineEmits(['close', 'submit'])
  121. const props = defineProps({
  122. show: {
  123. type: Boolean,
  124. default: false
  125. },
  126. isEditing: {
  127. type: Boolean,
  128. default: false
  129. },
  130. data: {
  131. type: Object,
  132. default: () => {}
  133. }
  134. })
  135. const handleShow = (show: boolean) => {
  136. if (!show) {
  137. emits('close')
  138. }
  139. }
  140. const cardList = reactive([
  141. {
  142. name: '智芳',
  143. desc: '自然舒适',
  144. type: 0,
  145. icon: ''
  146. },
  147. {
  148. name: '智华',
  149. desc: '自然舒适',
  150. type: 1,
  151. icon: ''
  152. },
  153. {
  154. name: '智付',
  155. desc: '支付播报 特色声音',
  156. type: 2,
  157. icon: ''
  158. },
  159. {
  160. name: '智柯',
  161. desc: '自然轻快',
  162. type: 3,
  163. icon: ''
  164. }
  165. ])
  166. const handleCharterSelect = (card) => {
  167. console.log('handleCharterSelect', card)
  168. form.voiceType = card.type
  169. }
  170. const handleSave = async () => {
  171. const data: SaveTOTTSParams = {
  172. ...form,
  173. num: main.sceneCode
  174. }
  175. await saveTOTTS(data)
  176. // console.log(res)
  177. message.success('新增成功!')
  178. emits('submit')
  179. }
  180. const activeType = computed(() => (type) => form.voiceType === type)
  181. watchEffect(() => {
  182. showModal.value = props.show
  183. if (props.isEditing) {
  184. formId.value = props.data.id
  185. console.log('props.data', props.data)
  186. form.document = props.data.document
  187. // form.document = props.data.document
  188. }
  189. })
  190. </script>
  191. <style scoped lang="scss">
  192. .close-icon {
  193. cursor: pointer;
  194. }
  195. .card-select {
  196. min-height: 200px;
  197. .card-item {
  198. &:hover {
  199. cursor: pointer;
  200. border-color: var(--primary-color);
  201. }
  202. &.active {
  203. border-color: var(--primary-color);
  204. }
  205. }
  206. }
  207. </style>