Compare commits
No commits in common. "seedance" and "master" have entirely different histories.
|
|
@ -1,27 +0,0 @@
|
|||
.DS_Store
|
||||
node_modules/
|
||||
unpackage
|
||||
/dist/
|
||||
/manager/dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
/test/unit/coverage/
|
||||
/test/e2e/reports/
|
||||
selenium-debug.log
|
||||
nodejs/public/uploads
|
||||
*.zip
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
package-lock.json
|
||||
.history
|
||||
/unpackage/resources/
|
||||
/unpackage/dist/dev
|
||||
/unpackage/dist/build/.automator
|
||||
/unpackage/dist/build/app-plus
|
||||
*.lock
|
||||
|
|
@ -5,8 +5,6 @@
|
|||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/python" />
|
||||
<excludePattern pattern="*.zip" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ VUE_APP_TITLE = 管理系统
|
|||
ENV = 'production'
|
||||
|
||||
# 若依管理系统/生产环境
|
||||
VUE_APP_BASE_API = 'http://47.86.170.114:8011'
|
||||
VUE_APP_BASE_API = 'https://admin-api.undressing.name'
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ yarn-error.log*
|
|||
tests/**/coverage/
|
||||
tests/e2e/reports
|
||||
selenium-debug.log
|
||||
*.zip
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
|
|
|
|||
|
|
@ -4,4 +4,3 @@ VITE_AMAP_SAFE_KEY = 23d3fdbc6b4eaf65d4a82a16510938c9
|
|||
VITE_REGISTER_SOURCE = ALL
|
||||
#VITE_REGISTER_SOURCE = XM001
|
||||
VITE_SHOW_PAY = SUCCESS
|
||||
VITE_API_URL = http://47.86.170.114:8011/api
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
# 端口
|
||||
VITE_PORT = 8887
|
||||
VITE_API_URL = http://47.86.170.114:8011/api
|
||||
VITE_API_URL = https://api.undressing.name/api
|
||||
|
|
@ -10,7 +10,7 @@ yarn-error.log*
|
|||
/test/e2e/reports/
|
||||
selenium-debug.log
|
||||
nodejs/public/uploads
|
||||
*.zip
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -615,4 +615,4 @@
|
|||
right: 15px
|
||||
}
|
||||
|
||||
/* Quill core styles - source map removed to fix build error */
|
||||
/*# sourceMappingURL=quill.core.css.map*/
|
||||
|
|
@ -1286,4 +1286,4 @@
|
|||
border: 1px solid #ccc
|
||||
}
|
||||
|
||||
/* Quill snow styles - source map removed to fix build error */
|
||||
/*# sourceMappingURL=quill.snow.css.map*/
|
||||
|
|
@ -8,6 +8,10 @@
|
|||
fullscreen
|
||||
:class="`${prefixCls}-wrapper`"
|
||||
:modal-class="`${prefixCls}-dialog`">
|
||||
<mf-video
|
||||
autoplay
|
||||
:controls="false"
|
||||
modelValue="https://images.iqyjsnwv.com/tmp/hello-BCSGJ8fP.mp4" />
|
||||
<div :class="`${prefixCls}-shadow`">
|
||||
<div :class="`${prefixCls}-title`">
|
||||
{{ $t('common.fbTitle') }}
|
||||
|
|
|
|||
|
|
@ -462,11 +462,12 @@ export default {
|
|||
// 获取国家名称(根据当前语言)
|
||||
getCountryName(country) {
|
||||
if (!country) return ''
|
||||
// 繁体中文显示中文名称,其他语言显示英文名称
|
||||
if (this.lang === 'zh_HK') {
|
||||
return country.name || country.nameEn || ''
|
||||
// 如果是英文,显示英文名称
|
||||
if (this.lang === 'en_US') {
|
||||
return country.nameEn || country.name
|
||||
}
|
||||
return country.nameEn || country.name || ''
|
||||
// 默认显示中文名称
|
||||
return country.name
|
||||
},
|
||||
// 国家下拉框搜索过滤
|
||||
filterCountry(inputValue, option) {
|
||||
|
|
|
|||
|
|
@ -1,412 +0,0 @@
|
|||
<template>
|
||||
<div class="rich-editor-root">
|
||||
<!-- 工具栏 -->
|
||||
<div class="toolbar">
|
||||
<button class="tool-btn" type="button" @click="execCommand('bold')"><b>B</b></button>
|
||||
<button class="tool-btn" type="button" @click="execCommand('italic')"><i>I</i></button>
|
||||
<button class="tool-btn" type="button" @click="openImagePicker">{{ $t('common.insertImage') || '插入图片' }}</button>
|
||||
<button class="tool-btn" type="button" @click="clear">清空</button>
|
||||
</div>
|
||||
|
||||
<!-- 隐藏的文件输入 -->
|
||||
<input
|
||||
ref="fileInputRef"
|
||||
class="hidden-input"
|
||||
type="file"
|
||||
accept="image/*"
|
||||
multiple
|
||||
@change="handleSelectFiles"
|
||||
/>
|
||||
|
||||
<!-- 编辑器区域 -->
|
||||
<div
|
||||
ref="editorRef"
|
||||
class="user-input rich-editor"
|
||||
contenteditable="true"
|
||||
:data-placeholder="placeholder || '请输入文本...'"
|
||||
@input="handleInput"
|
||||
@keyup="handleKeyup"
|
||||
@click="handleEditorClick"
|
||||
@keydown="handleKeydown"
|
||||
></div>
|
||||
|
||||
<!-- @ 图片选择面板 -->
|
||||
<div v-if="mentionVisible" class="mention-panel">
|
||||
<div
|
||||
v-for="(item, idx) in mentionImageList"
|
||||
:key="item.url"
|
||||
class="mention-item"
|
||||
@mousedown.prevent="insertMentionImage(item)"
|
||||
>
|
||||
<img :src="item.url" class="mention-thumb" />
|
||||
<span class="mention-label">@图{{ idx + 1 }}</span>
|
||||
</div>
|
||||
<div v-if="mentionImageList.length === 0" class="mention-empty">
|
||||
{{ $t('common.noImageToMention') || '暂无可引用图片' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { uploadFile } from '@/utils/file'
|
||||
|
||||
export default {
|
||||
name: 'RichTextEditor',
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入文本生成视频...'
|
||||
},
|
||||
uploadedImages: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
emits: ['update:modelValue', 'text-change', 'image-upload'],
|
||||
setup(props, { emit }) {
|
||||
const editorRef = ref(null)
|
||||
const fileInputRef = ref(null)
|
||||
const savedSelectionRange = ref(null)
|
||||
const mentionVisible = ref(false)
|
||||
const mentionImageList = ref([])
|
||||
const MAX_IMAGE_COUNT = 4
|
||||
|
||||
// 执行编辑器命令
|
||||
const execCommand = (command) => {
|
||||
if (!editorRef.value) return
|
||||
editorRef.value.focus()
|
||||
document.execCommand(command, false, null)
|
||||
handleInput()
|
||||
}
|
||||
|
||||
// 打开图片选择器
|
||||
const openImagePicker = () => {
|
||||
if (fileInputRef.value) {
|
||||
fileInputRef.value.click()
|
||||
}
|
||||
}
|
||||
|
||||
// 处理文件选择 - 上传到服务器
|
||||
const handleSelectFiles = async (event) => {
|
||||
const files = event.target.files
|
||||
if (!files.length) return
|
||||
|
||||
for (let file of files) {
|
||||
if (file.type.startsWith('image/')) {
|
||||
try {
|
||||
// 显示上传中提示
|
||||
const loading = window.$message ? window.$message.loading('上传中...') : null
|
||||
|
||||
// 上传到后端
|
||||
const res = await uploadFile({
|
||||
url: '/api/cos/upload', // 使用腾讯云COS上传接口
|
||||
file: file,
|
||||
name: 'file'
|
||||
})
|
||||
|
||||
if (res && res.code === 200 && res.data) {
|
||||
const imageUrl = typeof res.data === 'string' ? res.data : (res.data.url || res.data)
|
||||
insertImage(imageUrl, file.name)
|
||||
|
||||
// 通知父组件有新图片上传成功(用于@功能)
|
||||
emit('image-upload', { url: imageUrl, name: file.name })
|
||||
} else {
|
||||
console.error('上传失败:', res)
|
||||
alert('图片上传失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('上传图片出错:', error)
|
||||
alert('图片上传失败: ' + (error.message || '未知错误'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 清空input
|
||||
event.target.value = ''
|
||||
}
|
||||
|
||||
// 插入图片
|
||||
const insertImage = (url, name = 'image') => {
|
||||
if (!editorRef.value) return
|
||||
|
||||
editorRef.value.focus()
|
||||
const selection = window.getSelection()
|
||||
if (!selection) return
|
||||
|
||||
const img = document.createElement('img')
|
||||
img.src = url
|
||||
img.alt = name
|
||||
img.style.maxWidth = '100%'
|
||||
img.style.height = 'auto'
|
||||
img.style.margin = '4px 0'
|
||||
img.setAttribute('data-image-name', name)
|
||||
|
||||
const range = selection.getRangeAt(0)
|
||||
range.deleteContents()
|
||||
range.insertNode(img)
|
||||
|
||||
// 添加空格
|
||||
const space = document.createTextNode(' ')
|
||||
range.setStartAfter(img)
|
||||
range.setEndAfter(img)
|
||||
range.insertNode(space)
|
||||
|
||||
handleInput()
|
||||
}
|
||||
|
||||
// 处理输入
|
||||
const handleInput = () => {
|
||||
if (!editorRef.value) return
|
||||
const content = editorRef.value.innerHTML
|
||||
emit('update:modelValue', content)
|
||||
emit('text-change', content)
|
||||
}
|
||||
|
||||
// 处理按键
|
||||
const handleKeyup = (e) => {
|
||||
if (e.key === '@') {
|
||||
showMentionPanel()
|
||||
} else if (e.key === 'Escape' && mentionVisible.value) {
|
||||
mentionVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeydown = (e) => {
|
||||
if (e.key === '@') {
|
||||
// 保存当前选择位置
|
||||
const selection = window.getSelection()
|
||||
if (selection && selection.rangeCount > 0) {
|
||||
savedSelectionRange.value = selection.getRangeAt(0).cloneRange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 显示 @ 面板
|
||||
const showMentionPanel = () => {
|
||||
if (props.uploadedImages && props.uploadedImages.length > 0) {
|
||||
mentionImageList.value = props.uploadedImages.slice(0, MAX_IMAGE_COUNT)
|
||||
mentionVisible.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 插入 @ 图片
|
||||
const insertMentionImage = (imageItem) => {
|
||||
if (!editorRef.value || !savedSelectionRange.value) {
|
||||
mentionVisible.value = false
|
||||
return
|
||||
}
|
||||
|
||||
editorRef.value.focus()
|
||||
|
||||
const selection = window.getSelection()
|
||||
if (selection) {
|
||||
selection.removeAllRanges()
|
||||
selection.addRange(savedSelectionRange.value)
|
||||
}
|
||||
|
||||
const img = document.createElement('img')
|
||||
img.src = imageItem.url
|
||||
img.alt = '@图片'
|
||||
img.style.maxWidth = '60px'
|
||||
img.style.height = 'auto'
|
||||
img.style.verticalAlign = 'middle'
|
||||
img.setAttribute('data-mention', 'true')
|
||||
|
||||
const range = savedSelectionRange.value
|
||||
range.deleteContents()
|
||||
range.insertNode(img)
|
||||
|
||||
// 添加空格
|
||||
const space = document.createTextNode(' ')
|
||||
range.setStartAfter(img)
|
||||
range.setEndAfter(img)
|
||||
range.insertNode(space)
|
||||
|
||||
mentionVisible.value = false
|
||||
handleInput()
|
||||
}
|
||||
|
||||
// 清空编辑器
|
||||
const clear = () => {
|
||||
if (!editorRef.value) return
|
||||
editorRef.value.innerHTML = ''
|
||||
handleInput()
|
||||
}
|
||||
|
||||
// 处理编辑器点击
|
||||
const handleEditorClick = () => {
|
||||
if (mentionVisible.value) {
|
||||
mentionVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 监听 props 变化
|
||||
watch(() => props.modelValue, (newValue) => {
|
||||
if (editorRef.value && editorRef.value.innerHTML !== newValue) {
|
||||
editorRef.value.innerHTML = newValue || ''
|
||||
}
|
||||
})
|
||||
|
||||
// 监听上传的图片列表更新
|
||||
watch(() => props.uploadedImages, (newImages) => {
|
||||
mentionImageList.value = newImages || []
|
||||
}, { immediate: true })
|
||||
|
||||
onMounted(() => {
|
||||
if (editorRef.value) {
|
||||
editorRef.value.innerHTML = props.modelValue || ''
|
||||
|
||||
// 添加粘贴事件处理
|
||||
editorRef.value.addEventListener('paste', (e) => {
|
||||
const items = e.clipboardData.items
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf('image') !== -1) {
|
||||
const blob = items[i].getAsFile()
|
||||
const reader = new FileReader()
|
||||
reader.onload = (event) => {
|
||||
insertImage(event.target.result, 'pasted-image')
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
e.preventDefault()
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
editorRef,
|
||||
fileInputRef,
|
||||
mentionVisible,
|
||||
mentionImageList,
|
||||
execCommand,
|
||||
openImagePicker,
|
||||
handleSelectFiles,
|
||||
handleInput,
|
||||
handleKeyup,
|
||||
handleKeydown,
|
||||
handleEditorClick,
|
||||
insertMentionImage,
|
||||
clear
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.rich-editor-root {
|
||||
position: relative;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: #1a1b20;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
|
||||
.tool-btn {
|
||||
padding: 6px 12px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255,255,255,0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rich-editor {
|
||||
min-height: 120px;
|
||||
padding: 12px;
|
||||
background: #1a1b20;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
overflow-y: auto;
|
||||
|
||||
&:empty:before {
|
||||
content: attr(data-placeholder);
|
||||
color: #666;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 4px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.mention-panel {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
background: #1f2128;
|
||||
border: 1px solid #3a3d47;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 1000;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
width: 280px;
|
||||
|
||||
.mention-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||
|
||||
&:hover {
|
||||
background: #2a2d38;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.mention-thumb {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.mention-label {
|
||||
color: #a1a4b3;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.mention-empty {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.hidden-input {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -237,18 +237,11 @@ export default {
|
|||
{content}
|
||||
</div></div>
|
||||
}
|
||||
{/* 图片预览区域 - 点击框体可替换 */}
|
||||
{/* 图片预览区域 */}
|
||||
{!this.$datas.isEmpty(mValue) && (
|
||||
<div class="mf-image-upload-draggable-preview">
|
||||
{mValue.map(item => {
|
||||
return <div
|
||||
class="mf-image-upload-draggable-preview-item mf-image-upload-draggable-replace"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
if (!readonly && !this.disabled) this.triggerUpload()
|
||||
}}
|
||||
>
|
||||
return <div class="mf-image-upload-draggable-preview-item">
|
||||
<a-image
|
||||
width="100%"
|
||||
height="100%"
|
||||
|
|
@ -257,16 +250,6 @@ export default {
|
|||
preview={true}
|
||||
/>
|
||||
<div class="mf-image-upload-draggable-preview-mask">
|
||||
{!readonly && (
|
||||
<mf-icon
|
||||
value="icon-edit"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
this.triggerUpload()
|
||||
}}
|
||||
title={this.$t('common.replaceImage') || '替换'}
|
||||
/>
|
||||
)}
|
||||
{item.type !== '.pdf' && (
|
||||
<mf-icon
|
||||
value="icon-eye"
|
||||
|
|
@ -314,52 +297,6 @@ export default {
|
|||
</div>
|
||||
}
|
||||
},
|
||||
// 触发文件选择(用于替换已上传图片)
|
||||
triggerUpload() {
|
||||
if (this.readonly || this.disabled) return
|
||||
const mValue = this.getValue()
|
||||
// draggable 且已有图片时,用专用替换 input,避免 a-upload 在 limit 满时不渲染 input
|
||||
if (this.listType === 'draggable' && mValue.length > 0 && this.$refs.replaceInput) {
|
||||
this.$refs.replaceInput.value = ''
|
||||
this.$refs.replaceInput.click()
|
||||
return
|
||||
}
|
||||
const el = this.$refs.mfUpload?.$el
|
||||
const input = el?.querySelector?.('input[type="file"]')
|
||||
if (input) {
|
||||
input.value = ''
|
||||
input.click()
|
||||
}
|
||||
},
|
||||
// 替换时选择文件后手动上传
|
||||
handleReplaceFileChange(e) {
|
||||
const file = e.target.files[0]
|
||||
if (!file) return
|
||||
if (file.size / 1024 / 1024 > 10) {
|
||||
this.$message.error('文件大小不能超过10M')
|
||||
e.target.value = ''
|
||||
return
|
||||
}
|
||||
this.$emit('beforeUpload', file)
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
const action = import.meta.env.MODE === 'production' ? 'api/file/upload' : 'dev-api/api/file/upload'
|
||||
const headers = { ...this.headers }
|
||||
delete headers['Content-Type']
|
||||
fetch(action, { method: 'POST', body: formData, headers })
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if (data.code === 200 && data.url) {
|
||||
const url = this.getImageUrl(data.url)
|
||||
this.handleChange({ url, name: file.name })
|
||||
this.$emit('success', data.url, file)
|
||||
} else {
|
||||
this.$message.error(data.msg || data.url || '上传失败')
|
||||
}
|
||||
})
|
||||
.catch(() => this.$message.error('上传失败'))
|
||||
.finally(() => { e.target.value = '' })
|
||||
},
|
||||
handlePreview() {
|
||||
let images = this.getValue().map((i) => i.url)
|
||||
this.$viewerApi({
|
||||
|
|
@ -549,26 +486,14 @@ export default {
|
|||
}
|
||||
|
||||
return (
|
||||
<div class={`${prefixCls}-wrap`}>
|
||||
{listType === 'draggable' && (
|
||||
<input
|
||||
ref="replaceInput"
|
||||
type="file"
|
||||
accept={accept}
|
||||
style={{ position: 'absolute', opacity: 0, width: 0, height: 0, pointerEvents: 'none' }}
|
||||
onChange={this.handleReplaceFileChange}
|
||||
/>
|
||||
)}
|
||||
<a-upload
|
||||
ref="mfUpload"
|
||||
class={wrapCls}
|
||||
action={action}
|
||||
name="file"
|
||||
headers={headers}
|
||||
{...imageUploadProps}
|
||||
v-slots={slots}
|
||||
/>
|
||||
</div>
|
||||
<a-upload
|
||||
ref="mfUpload"
|
||||
class={wrapCls}
|
||||
action={action}
|
||||
name="file"
|
||||
headers={headers}
|
||||
{...imageUploadProps}
|
||||
v-slots={slots}></a-upload>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,9 +112,6 @@
|
|||
&-item {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
&.mf-image-upload-draggable-replace {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&-mask {
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -1,179 +0,0 @@
|
|||
export default {
|
||||
image1: 'خلع بضغطة واحدة',
|
||||
image2: 'صورة إلى صورة 2',
|
||||
uploadImage: 'رفع صورة',
|
||||
uploadImageTip: 'PNG/JPG، بحد أقصى 10 ميجا',
|
||||
uploadPlaceholder: 'انقر لرفع صورة',
|
||||
selectImageSource: 'اختر مصدر الصورة',
|
||||
selectTemplate: 'اختر القالب',
|
||||
reselectTemplate: 'إعادة اختيار القالب',
|
||||
noTemplates: 'لا توجد قوالب',
|
||||
tag1: 'نوع الوسم 1',
|
||||
tag2: 'نوع الوسم 2',
|
||||
tag3: 'نوع الوسم 3',
|
||||
generateImage: 'إنشاء الآن (يخصم {score} من الرصيد)',
|
||||
generateImageNow: 'إنشاء الآن',
|
||||
generateTip: 'بعد الإرسال يمكنك المشاهدة في "أعمالي"',
|
||||
generateVideo: 'إنشاء فيديو',
|
||||
imageFace: 'تبديل الوجه في صورة',
|
||||
videoFace: 'تبديل الوجه في فيديو',
|
||||
uploadImageFace: 'انقر لرفع صورة الوجه',
|
||||
uploadTemplate: 'انقر لرفع قالب مخصص',
|
||||
textPlaceholder: 'صف الصورة التي تريد إنشاءها',
|
||||
uploadImageError: 'يرجى رفع صورة',
|
||||
replaceImage: 'استبدال الصورة',
|
||||
uploadFaceImageError: 'يرجى رفع صورة الوجه',
|
||||
uploadTemplateError: 'يرجى رفع قالب مخصص',
|
||||
textError: 'يرجى إدخال النص التوجيهي',
|
||||
textVideoPlaceholder: 'صف الفيديو الذي تريد إنشاءه',
|
||||
uploadFirstPlaceholder: 'انقر لرفع الإطار الأول',
|
||||
uploadLastPlaceholder: 'انقر لرفع الإطار الأخير',
|
||||
uploadFirstImageError: 'يرجى رفع صورة الإطار الأول',
|
||||
uploadWaitImageError: 'يرجى انتظار انتهاء الرفع',
|
||||
saveVideo: 'تحميل الفيديو',
|
||||
videoLoadingText: 'جاري إنشاء الفيديو...',
|
||||
viewVideo: 'عرض الفيديو',
|
||||
changeFacePrompt: 'أخذ الوجه من الصورة الثانية واستبداله بالوجه في الأولى',
|
||||
rechartTip1: 'عند الشحن via المحفظة تأكد من شبكة المحفظة.',
|
||||
rechartTip2: 'قد يتأخر الشحن؛ انتظر 3–5 دقائق ثم حدّث.',
|
||||
walletAddr: 'عنوان المحفظة:',
|
||||
fbTitle: 'تحذير! هذا الموقع للبالغين فقط!',
|
||||
fbContent: 'بالدخول أؤكد أن عمري 18 سنة أو أكثر',
|
||||
fbCancel: 'أقل من 18',
|
||||
fbOK: 'عمري 18+',
|
||||
sorry: 'عذراً!',
|
||||
useLess: 'لا يمكنك استخدام هذا الموقع...',
|
||||
loginAccount: 'تسجيل الدخول',
|
||||
logout: 'تسجيل الخروج',
|
||||
userEmailPlaceholder: 'أدخل البريد أو اسم المستخدم',
|
||||
passwordPlaceholder: 'أدخل كلمة المرور',
|
||||
forgetPassword: 'نسيت كلمة المرور؟',
|
||||
register: 'التسجيل',
|
||||
login: 'دخول',
|
||||
forgotPassword: 'نسيت كلمة المرور',
|
||||
registerAccount: 'إنشاء حساب',
|
||||
usernamePlaceholder: 'أدخل اسم المستخدم',
|
||||
codePlaceholder: 'أدخل رمز التحقق',
|
||||
confirmPasswordPlaceholder: 'تأكيد كلمة المرور',
|
||||
backToLogin: 'العودة لتسجيل الدخول',
|
||||
send: 'إرسال',
|
||||
emailValidPlaceholder: 'أدخل بريداً إلكترونياً صحيحاً',
|
||||
confirmPwdValidMsg: 'كلمات المرور غير متطابقة',
|
||||
editPassword: 'تغيير كلمة المرور',
|
||||
recharge: 'شحن',
|
||||
myAccount: 'حسابي',
|
||||
moneyInvite: 'دعوة مكافآت',
|
||||
rechargeRecord: 'سجل الشحن',
|
||||
resumeRecord: 'سجل الاستهلاك',
|
||||
inviteRecord: 'سجل الدعوات',
|
||||
username: 'اسم المستخدم',
|
||||
userId: 'معرف المستخدم',
|
||||
accountAmount: 'الرصيد',
|
||||
editUserInfo: 'تعديل البيانات',
|
||||
contact: 'تواصل معنا',
|
||||
backToUser: 'رجوع',
|
||||
moneyTips: 'عند دعوة صديق للتسجيل تحصل على {rate} من مبلغ شحنه في كل مرة.',
|
||||
inviteCode: 'رمز الدعوة',
|
||||
inviteLink: 'رابط الدعوة',
|
||||
saveImage: 'حفظ الصورة',
|
||||
totalAmount: 'إجمالي الشحن',
|
||||
amount: 'المبلغ',
|
||||
sendAmount: 'مبلغ الهدية',
|
||||
rechargeType: 'طريقة الشحن',
|
||||
rechargeTime: 'وقت الشحن',
|
||||
emptyText: 'لا توجد بيانات',
|
||||
product: 'عمل',
|
||||
resumeAmount: 'المبلغ المستهلك',
|
||||
productType: 'نوع العمل',
|
||||
productTime: 'وقت الإنشاء',
|
||||
totalReward: 'رصيد المكافآت',
|
||||
rewardAmount: 'مبلغ المكافأة',
|
||||
rewardTime: 'وقت المكافأة',
|
||||
reSend: 'إعادة الإرسال',
|
||||
registerSuccessfully: 'تم التسجيل بنجاح',
|
||||
loginSuccessfully: 'تم تسجيل الدخول',
|
||||
passwordResetSuccessfully: 'تم إعادة تعيين كلمة المرور',
|
||||
rechargeSuccessfully: 'تم الشحن بنجاح',
|
||||
avatar: 'الصورة الرمزية',
|
||||
input: 'أدخل',
|
||||
save: 'حفظ',
|
||||
editEmail: 'تغيير البريد',
|
||||
editEmailSuccessfully: 'تم تحديث البريد',
|
||||
updateAvatarSuccessfully: 'تم تحديث الصورة الرمزية',
|
||||
balenceLow: 'رصيدك غير كافٍ، يرجى الشحن',
|
||||
confirm: 'تأكيد',
|
||||
createFailed: 'فشل الإنشاء، تمت إعادة الرصيد',
|
||||
notice: 'تنبيه',
|
||||
oldPasswordPlaceholder: 'أدخل كلمة المرور القديمة',
|
||||
newpasswordPlaceholder: 'أدخل كلمة المرور الجديدة',
|
||||
switchPageTip: 'الفيديو قيد الإنشاء؛ اخرج وتحقق من سجل الاستهلاك.',
|
||||
loginless: 'انتهت الجلسة! يرجى تسجيل الدخول مجدداً.',
|
||||
createVideo: 'إنشاء فيديو (يخصم {price} من الرصيد)',
|
||||
ok: 'تأكيد',
|
||||
rechartNotice: 'تعليمات الشحن',
|
||||
rechargeNotice1: '1. يُضاف الشحن فوراً. إن لم يتغير الرصيد حدّث الصفحة.',
|
||||
rechargeNotice2: '2. الباقات المحدودة عروض؛ يمكنك الشحن أكثر من مرة.',
|
||||
rechargeNotice3: '3. الرصيد المشحون لا ينتهي صلاحيته.',
|
||||
rechargeNotice4: 'راجع الباقة قبل الشراء؛ لا استرداد.',
|
||||
rechargeLeft: 'الرصيد',
|
||||
dollor: 'USD',
|
||||
isDevelop: 'قيد التطوير.',
|
||||
copySuccessfully: 'تم النسخ',
|
||||
copyLink: 'نسخ الرابط',
|
||||
goPay: 'الذهاب للدفع',
|
||||
filePreview: 'معاينة',
|
||||
doSame: 'عمل نسخة مشابهة',
|
||||
saveQRCode: 'حفظ رمز QR',
|
||||
invitationCodePlaceholder: 'أدخل رمز الدعوة',
|
||||
testRecharge: 'شحن تجريبي',
|
||||
orderNo: 'رقم الطلب',
|
||||
orderNoP: 'رقم الطلب مطلوب',
|
||||
emailNotExists: 'هذا البريد غير مسجّل',
|
||||
gearNotExists: 'خطة الشحن المختارة غير موجودة؛ اختر غيرها.',
|
||||
myProduct: 'أعمالي',
|
||||
permissionError: 'إجمالي شحنك {total}، لا يكفي للمعاينة.',
|
||||
createTagFailed: 'فشل الإنشاء؛ حدّث وجرب مرة أخرى.',
|
||||
loadingText: 'جاري التحميل...',
|
||||
hasMore: 'اسحب لأعلى للمزيد',
|
||||
noMore: 'لا مزيد',
|
||||
giftAmount: 'المبلغ المُستَوفى',
|
||||
cardNo: 'رقم البطاقة',
|
||||
cardName: 'اسم صاحب البطاقة',
|
||||
cardNoRequired: 'أدخل رقم البطاقة',
|
||||
cardNameRequired: 'أدخل اسم صاحب البطاقة',
|
||||
rechargeFailed: 'فشل الشحن',
|
||||
vmCardInfo: 'بيانات البطاقة',
|
||||
cardNumber: 'رقم البطاقة',
|
||||
cardNumberPlaceholder: 'أدخل رقم البطاقة',
|
||||
cardNumberRequired: 'أدخل رقم البطاقة',
|
||||
cardNumberInvalid: 'رقم البطاقة يجب أن يكون 13–19 رقماً',
|
||||
cvc: 'CVC',
|
||||
cvcPlaceholder: 'أدخل CVC',
|
||||
cvcRequired: 'أدخل CVC',
|
||||
cvcInvalid: 'CVC يجب أن يكون 3 أرقام',
|
||||
expYear: 'سنة انتهاء الصلاحية',
|
||||
expYearPlaceholder: 'أدخل السنة (مثل 2027)',
|
||||
expYearRequired: 'أدخل سنة انتهاء الصلاحية',
|
||||
expYearInvalid: 'السنة يجب أن تكون 4 أرقام',
|
||||
expMonth: 'شهر انتهاء الصلاحية',
|
||||
expMonthPlaceholder: 'اختر الشهر',
|
||||
expMonthRequired: 'اختر الشهر',
|
||||
email: 'البريد',
|
||||
emailPlaceholder: 'أدخل البريد',
|
||||
emailRequired: 'أدخل البريد',
|
||||
emailInvalid: 'صيغة البريد غير صحيحة',
|
||||
emailMaxLength: 'البريد لا يتجاوز 30 حرفاً',
|
||||
firstName: 'الاسم الأول',
|
||||
firstNamePlaceholder: 'أدخل الاسم الأول',
|
||||
firstNameRequired: 'أدخل الاسم الأول',
|
||||
firstNameMaxLength: 'الاسم لا يتجاوز 30 حرفاً',
|
||||
lastName: 'اسم العائلة',
|
||||
lastNamePlaceholder: 'أدخل اسم العائلة',
|
||||
lastNameRequired: 'أدخل اسم العائلة',
|
||||
lastNameMaxLength: 'اسم العائلة لا يتجاوز 30 حرفاً',
|
||||
country: 'الدولة',
|
||||
countryPlaceholder: 'اختر الدولة',
|
||||
countryRequired: 'اختر الدولة',
|
||||
submit: 'إرسال',
|
||||
cancel: 'إلغاء'
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import route from './route'
|
||||
import common from './common.js'
|
||||
|
||||
export default {
|
||||
route,
|
||||
common
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
index: 'الرئيسية',
|
||||
imageToImage: 'خلع بضغطة واحدة',
|
||||
imageToImage2: 'صورة إلى صورة 2',
|
||||
changeFace: 'تبديل الوجه',
|
||||
changeFaceVideo: 'تبديل الوجه في الفيديو',
|
||||
fastImage: 'إنشاء صورة',
|
||||
fastVideo: 'إنشاء فيديو',
|
||||
recharge: 'شحن سريع',
|
||||
help: 'مركز المساعدة',
|
||||
moneyInvite: 'دعوة مكافآت'
|
||||
}
|
||||
|
|
@ -23,7 +23,6 @@ export default {
|
|||
uploadTemplate: 'Click to upload custom template',
|
||||
textPlaceholder: 'Describe the image you want to generate',
|
||||
uploadImageError: 'Please upload an image',
|
||||
replaceImage: 'Replace image',
|
||||
textError: 'Please enter a prompt',
|
||||
textVideoPlaceholder: "Describe the video you want to generate",
|
||||
uploadFirstPlaceholder: 'Click to upload first frame',
|
||||
|
|
@ -143,14 +142,6 @@ export default {
|
|||
cardNoRequired: 'Please enter card number',
|
||||
cardNameRequired: 'Please enter cardholder name',
|
||||
rechargeFailed: 'Recharge failed',
|
||||
// Model selection
|
||||
selectModel: 'Select Model',
|
||||
seedance20: 'Seedance 2.0',
|
||||
seedance20Fast: 'Seedance 2.0 Fast',
|
||||
// Rich text editor
|
||||
insertImage: 'Insert Image',
|
||||
mentionImage: 'Mention Image',
|
||||
noImageToMention: 'No images to mention',
|
||||
// VM支付相关
|
||||
vmCardInfo: 'Credit Card Information',
|
||||
cardNumber: 'Card Number',
|
||||
|
|
@ -183,9 +174,5 @@ export default {
|
|||
country: 'Country',
|
||||
countryPlaceholder: 'Select country',
|
||||
countryRequired: 'Please select country',
|
||||
videoGen: 'Video Generation',
|
||||
uploadFirstImage: 'Upload Reference Image',
|
||||
insertImage: 'Insert Image',
|
||||
submit: 'Submit',
|
||||
cancel: 'Cancel'
|
||||
submit: 'Submit'
|
||||
}
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
export default {
|
||||
index: 'Home',
|
||||
imageToImage: 'Image-to-Image 1',
|
||||
imageToImage: 'One-click undressing',
|
||||
imageToImage2: 'Image-to-Image2',
|
||||
changeFace: 'Swap Face',
|
||||
changeFaceVideo: 'Swap Video Face',
|
||||
fastImage: 'Gen Image',
|
||||
fastVideo: 'Gen Video',
|
||||
videoGen: 'Video Generation',
|
||||
recharge: 'Quick Recharge',
|
||||
help: 'Help Center',
|
||||
moneyInvite: 'Reward Invitation'
|
||||
|
|
|
|||
|
|
@ -1,179 +0,0 @@
|
|||
export default {
|
||||
image1: 'Desvestir en un clic',
|
||||
image2: 'Imagen a Imagen 2',
|
||||
uploadImage: 'Subir imagen',
|
||||
uploadImageTip: 'Soporta PNG/JPG, máx. 10MB',
|
||||
uploadPlaceholder: 'Clic para subir imagen',
|
||||
selectImageSource: 'Seleccionar fuente de imagen',
|
||||
selectTemplate: 'Seleccionar plantilla',
|
||||
reselectTemplate: 'Reseleccionar plantilla',
|
||||
noTemplates: 'Sin plantillas',
|
||||
tag1: 'Tipo de etiqueta 1',
|
||||
tag2: 'Tipo de etiqueta 2',
|
||||
tag3: 'Tipo de etiqueta 3',
|
||||
generateImage: 'Generar ahora (consume {score} de saldo)',
|
||||
generateImageNow: 'Generar ahora',
|
||||
generateTip: 'Después de enviar, puede ver en "Mis obras"',
|
||||
generateVideo: 'Generar video',
|
||||
imageFace: 'Cambiar rostro en imagen',
|
||||
videoFace: 'Cambiar rostro en video',
|
||||
uploadImageFace: 'Clic para subir imagen de rostro',
|
||||
uploadTemplate: 'Clic para subir plantilla personalizada',
|
||||
textPlaceholder: 'Describa la imagen que desea generar',
|
||||
uploadImageError: 'Por favor suba una imagen',
|
||||
replaceImage: 'Reemplazar imagen',
|
||||
uploadFaceImageError: 'Por favor suba una imagen de rostro',
|
||||
uploadTemplateError: 'Por favor suba una plantilla personalizada',
|
||||
textError: 'Por favor escriba el texto de indicación',
|
||||
textVideoPlaceholder: 'Describa el video que desea generar',
|
||||
uploadFirstPlaceholder: 'Clic para subir imagen del primer frame',
|
||||
uploadLastPlaceholder: 'Clic para subir imagen del último frame',
|
||||
uploadFirstImageError: 'Por favor suba la imagen del primer frame',
|
||||
uploadWaitImageError: 'Espere a que termine la subida',
|
||||
saveVideo: 'Descargar video',
|
||||
videoLoadingText: 'Generando video...',
|
||||
viewVideo: 'Ver video',
|
||||
changeFacePrompt: 'Extraer el rostro de la segunda imagen y reemplazar en la primera',
|
||||
rechartTip1: 'Al recargar con transferencia de billetera, confirme la red del monedero.',
|
||||
rechartTip2: 'La recarga puede tardar; espere 3-5 minutos antes de actualizar.',
|
||||
walletAddr: 'Dirección del monedero:',
|
||||
fbTitle: 'Advertencia: este sitio es solo para adultos.',
|
||||
fbContent: 'Al entrar confirmo que tengo 18 años o más',
|
||||
fbCancel: 'Menor de 18',
|
||||
fbOK: 'Tengo 18 o más',
|
||||
sorry: '¡Lo sentimos!',
|
||||
useLess: 'No puede usar este sitio...',
|
||||
loginAccount: 'Iniciar sesión',
|
||||
logout: 'Cerrar sesión',
|
||||
userEmailPlaceholder: 'Introduzca correo o usuario',
|
||||
passwordPlaceholder: 'Introduzca contraseña',
|
||||
forgetPassword: '¿Olvidó la contraseña?',
|
||||
register: 'Registrarse',
|
||||
login: 'Iniciar sesión',
|
||||
forgotPassword: 'Olvidé la contraseña',
|
||||
registerAccount: 'Crear cuenta',
|
||||
usernamePlaceholder: 'Introduzca usuario',
|
||||
codePlaceholder: 'Introduzca código de verificación',
|
||||
confirmPasswordPlaceholder: 'Confirme la contraseña',
|
||||
backToLogin: 'Volver al inicio de sesión',
|
||||
send: 'Enviar',
|
||||
emailValidPlaceholder: 'Introduzca un correo válido',
|
||||
confirmPwdValidMsg: 'Las contraseñas no coinciden',
|
||||
editPassword: 'Cambiar contraseña',
|
||||
recharge: 'Recargar',
|
||||
myAccount: 'Mi cuenta',
|
||||
moneyInvite: 'Invitación con recompensa',
|
||||
rechargeRecord: 'Historial de recargas',
|
||||
resumeRecord: 'Historial de consumo',
|
||||
inviteRecord: 'Historial de invitaciones',
|
||||
username: 'Usuario',
|
||||
userId: 'ID de usuario',
|
||||
accountAmount: 'Saldo',
|
||||
editUserInfo: 'Editar datos',
|
||||
contact: 'Contacto',
|
||||
backToUser: 'Volver',
|
||||
moneyTips: 'Al invitar a un amigo a registrarse, obtiene {rate} de su recarga cada vez.',
|
||||
inviteCode: 'Código de invitación',
|
||||
inviteLink: 'Enlace de invitación',
|
||||
saveImage: 'Guardar imagen',
|
||||
totalAmount: 'Total recargado',
|
||||
amount: 'Monto',
|
||||
sendAmount: 'Monto de regalo',
|
||||
rechargeType: 'Método de recarga',
|
||||
rechargeTime: 'Fecha de recarga',
|
||||
emptyText: 'Sin datos',
|
||||
product: 'Obra',
|
||||
resumeAmount: 'Monto consumido',
|
||||
productType: 'Tipo de obra',
|
||||
productTime: 'Fecha de creación',
|
||||
totalReward: 'Saldo de recompensas',
|
||||
rewardAmount: 'Monto de recompensa',
|
||||
rewardTime: 'Fecha de recompensa',
|
||||
reSend: 'Reenviar',
|
||||
registerSuccessfully: 'Registro exitoso',
|
||||
loginSuccessfully: 'Sesión iniciada',
|
||||
passwordResetSuccessfully: 'Contraseña restablecida',
|
||||
rechargeSuccessfully: 'Recarga exitosa',
|
||||
avatar: 'Avatar',
|
||||
input: 'Introduzca',
|
||||
save: 'Guardar',
|
||||
editEmail: 'Cambiar correo',
|
||||
editEmailSuccessfully: 'Correo actualizado',
|
||||
updateAvatarSuccessfully: 'Avatar actualizado',
|
||||
balenceLow: 'Saldo insuficiente, recargue',
|
||||
confirm: 'Aceptar',
|
||||
createFailed: 'Error al generar, saldo devuelto',
|
||||
notice: 'Aviso',
|
||||
oldPasswordPlaceholder: 'Introduzca la contraseña anterior',
|
||||
newpasswordPlaceholder: 'Introduzca la nueva contraseña',
|
||||
switchPageTip: 'El video se está generando; salga y revise el historial de consumo.',
|
||||
loginless: 'Sesión expirada; inicie sesión de nuevo.',
|
||||
createVideo: 'Generar video (consume {price} de saldo)',
|
||||
ok: 'Aceptar',
|
||||
rechartNotice: 'Instrucciones de recarga',
|
||||
rechargeNotice1: '1. La recarga se acredita al instante. Si no cambia, actualice la página.',
|
||||
rechargeNotice2: '2. Los paquetes por tiempo limitado son promociones; puede recargar varias veces.',
|
||||
rechargeNotice3: '3. El saldo recargado no tiene límite de tiempo.',
|
||||
rechargeNotice4: 'Revise el paquete antes de comprar; no hay devoluciones.',
|
||||
rechargeLeft: 'Saldo',
|
||||
dollor: 'USD',
|
||||
isDevelop: 'En desarrollo.',
|
||||
copySuccessfully: 'Copiado',
|
||||
copyLink: 'Copiar enlace',
|
||||
goPay: 'Ir a pagar',
|
||||
filePreview: 'Vista previa',
|
||||
doSame: 'Hacer similar',
|
||||
saveQRCode: 'Guardar código QR',
|
||||
invitationCodePlaceholder: 'Introduzca código de invitación',
|
||||
testRecharge: 'Recarga de prueba',
|
||||
orderNo: 'Número de pedido',
|
||||
orderNoP: 'El número de pedido es obligatorio',
|
||||
emailNotExists: 'El correo no está registrado',
|
||||
gearNotExists: 'El plan de recarga no existe; elija otro.',
|
||||
myProduct: 'Mis obras',
|
||||
permissionError: 'Su recarga acumulada es {total}, no cumple para previsualizar.',
|
||||
createTagFailed: 'Error al generar; actualice e intente de nuevo.',
|
||||
loadingText: 'Cargando...',
|
||||
hasMore: 'Deslizar para más',
|
||||
noMore: 'No hay más',
|
||||
giftAmount: 'Monto acreditado',
|
||||
cardNo: 'Número de tarjeta',
|
||||
cardName: 'Nombre en tarjeta',
|
||||
cardNoRequired: 'Introduzca número de tarjeta',
|
||||
cardNameRequired: 'Introduzca nombre en tarjeta',
|
||||
rechargeFailed: 'Recarga fallida',
|
||||
vmCardInfo: 'Datos de tarjeta',
|
||||
cardNumber: 'Número de tarjeta',
|
||||
cardNumberPlaceholder: 'Introduzca número de tarjeta',
|
||||
cardNumberRequired: 'Introduzca número de tarjeta',
|
||||
cardNumberInvalid: 'El número debe tener 13-19 dígitos',
|
||||
cvc: 'CVC',
|
||||
cvcPlaceholder: 'Introduzca CVC',
|
||||
cvcRequired: 'Introduzca CVC',
|
||||
cvcInvalid: 'CVC debe ser 3 dígitos',
|
||||
expYear: 'Año de vencimiento',
|
||||
expYearPlaceholder: 'Introduzca año (ej.: 2027)',
|
||||
expYearRequired: 'Introduzca año de vencimiento',
|
||||
expYearInvalid: 'El año debe ser 4 dígitos',
|
||||
expMonth: 'Mes de vencimiento',
|
||||
expMonthPlaceholder: 'Seleccione mes',
|
||||
expMonthRequired: 'Seleccione mes',
|
||||
email: 'Correo',
|
||||
emailPlaceholder: 'Introduzca correo',
|
||||
emailRequired: 'Introduzca correo',
|
||||
emailInvalid: 'Formato de correo no válido',
|
||||
emailMaxLength: 'Máx. 30 caracteres',
|
||||
firstName: 'Nombre',
|
||||
firstNamePlaceholder: 'Introduzca nombre',
|
||||
firstNameRequired: 'Introduzca nombre',
|
||||
firstNameMaxLength: 'Máx. 30 caracteres',
|
||||
lastName: 'Apellido',
|
||||
lastNamePlaceholder: 'Introduzca apellido',
|
||||
lastNameRequired: 'Introduzca apellido',
|
||||
lastNameMaxLength: 'Máx. 30 caracteres',
|
||||
country: 'País',
|
||||
countryPlaceholder: 'Seleccione país',
|
||||
countryRequired: 'Seleccione país',
|
||||
submit: 'Enviar',
|
||||
cancel: 'Cancelar'
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import route from './route'
|
||||
import common from './common.js'
|
||||
|
||||
export default {
|
||||
route,
|
||||
common
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
index: 'Inicio',
|
||||
imageToImage: 'Desvestir en un clic',
|
||||
imageToImage2: 'Imagen a Imagen 2',
|
||||
changeFace: 'Cambiar rostro',
|
||||
changeFaceVideo: 'Cambiar rostro en video',
|
||||
fastImage: 'Generar imagen',
|
||||
fastVideo: 'Generar video',
|
||||
recharge: 'Recarga rápida',
|
||||
help: 'Centro de ayuda',
|
||||
moneyInvite: 'Invitación con recompensa'
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
export default {
|
||||
image1: 'Déshabiller en un clic',
|
||||
image2: 'Image vers Image 2',
|
||||
uploadImage: 'Télécharger une image',
|
||||
uploadImageTip: 'PNG/JPG, max. 10 Mo',
|
||||
uploadPlaceholder: 'Cliquez pour télécharger',
|
||||
selectImageSource: 'Choisir la source de l\'image',
|
||||
selectTemplate: 'Choisir un modèle',
|
||||
reselectTemplate: 'Resélectionner un modèle',
|
||||
noTemplates: 'Aucun modèle',
|
||||
tag1: 'Type d\'étiquette 1',
|
||||
tag2: 'Type d\'étiquette 2',
|
||||
tag3: 'Type d\'étiquette 3',
|
||||
generateImage: 'Générer maintenant (coûte {score} de solde)',
|
||||
generateImageNow: 'Générer maintenant',
|
||||
generateTip: 'Après envoi, voir dans « Mes œuvres »',
|
||||
generateVideo: 'Générer une vidéo',
|
||||
imageFace: 'Changer le visage sur image',
|
||||
videoFace: 'Changer le visage en vidéo',
|
||||
uploadImageFace: 'Cliquez pour télécharger une photo de visage',
|
||||
uploadTemplate: 'Cliquez pour télécharger un modèle personnalisé',
|
||||
textPlaceholder: 'Décrivez l\'image que vous voulez générer',
|
||||
uploadImageError: 'Veuillez télécharger une image',
|
||||
replaceImage: 'Remplacer l\'image',
|
||||
uploadFaceImageError: 'Veuillez télécharger une photo de visage',
|
||||
uploadTemplateError: 'Veuillez télécharger un modèle personnalisé',
|
||||
textError: 'Veuillez saisir le texte d\'invite',
|
||||
textVideoPlaceholder: 'Décrivez la vidéo que vous voulez générer',
|
||||
uploadFirstPlaceholder: 'Cliquez pour télécharger la première image',
|
||||
uploadLastPlaceholder: 'Cliquez pour télécharger la dernière image',
|
||||
uploadFirstImageError: 'Veuillez télécharger l\'image du premier plan',
|
||||
uploadWaitImageError: 'Veuillez attendre la fin du téléchargement',
|
||||
saveVideo: 'Télécharger la vidéo',
|
||||
videoLoadingText: 'Génération de la vidéo...',
|
||||
viewVideo: 'Voir la vidéo',
|
||||
changeFacePrompt: 'Extraire le visage de la 2e image et remplacer celui de la 1re',
|
||||
rechartTip1: 'Lors d\'une recharge par portefeuille, vérifiez le réseau du portefeuille.',
|
||||
rechartTip2: 'La recharge peut être retardée ; attendez 3–5 min avant d’actualiser.',
|
||||
walletAddr: 'Adresse du portefeuille : ',
|
||||
fbTitle: 'Attention ! Ce site est réservé aux adultes.',
|
||||
fbContent: 'En entrant je confirme avoir 18 ans ou plus',
|
||||
fbCancel: 'Moins de 18 ans',
|
||||
fbOK: 'J\'ai 18 ans ou plus',
|
||||
sorry: 'Désolé !',
|
||||
useLess: 'Vous ne pouvez pas utiliser ce site...',
|
||||
loginAccount: 'Connexion',
|
||||
logout: 'Déconnexion',
|
||||
userEmailPlaceholder: 'Saisissez l\'email ou l’identifiant',
|
||||
passwordPlaceholder: 'Saisissez le mot de passe',
|
||||
forgetPassword: 'Mot de passe oublié ?',
|
||||
register: 'S\'inscrire',
|
||||
login: 'Connexion',
|
||||
forgotPassword: 'Mot de passe oublié',
|
||||
registerAccount: 'Créer un compte',
|
||||
usernamePlaceholder: 'Saisissez l’identifiant',
|
||||
codePlaceholder: 'Saisissez le code de vérification',
|
||||
confirmPasswordPlaceholder: 'Confirmez le mot de passe',
|
||||
backToLogin: 'Retour à la connexion',
|
||||
send: 'Envoyer',
|
||||
emailValidPlaceholder: 'Saisissez un email valide',
|
||||
confirmPwdValidMsg: 'Les mots de passe ne correspondent pas',
|
||||
editPassword: 'Modifier le mot de passe',
|
||||
recharge: 'Recharger',
|
||||
myAccount: 'Mon compte',
|
||||
moneyInvite: 'Invitation avec récompense',
|
||||
rechargeRecord: 'Historique des recharges',
|
||||
resumeRecord: 'Historique des consommations',
|
||||
inviteRecord: 'Historique des invitations',
|
||||
username: 'Identifiant',
|
||||
userId: 'ID utilisateur',
|
||||
accountAmount: 'Solde',
|
||||
editUserInfo: 'Modifier les informations',
|
||||
contact: 'Nous contacter',
|
||||
backToUser: 'Retour',
|
||||
moneyTips: 'Quand vous parrainez un ami, vous gagnez {rate} de chaque recharge qu’il fait.',
|
||||
inviteCode: 'Code de parrainage',
|
||||
inviteLink: 'Lien d\'invitation',
|
||||
saveImage: 'Enregistrer l\'image',
|
||||
totalAmount: 'Total rechargé',
|
||||
amount: 'Montant',
|
||||
sendAmount: 'Montant offert',
|
||||
rechargeType: 'Méthode de recharge',
|
||||
rechargeTime: 'Date de recharge',
|
||||
emptyText: 'Aucune donnée',
|
||||
product: 'Œuvre',
|
||||
resumeAmount: 'Montant consommé',
|
||||
productType: 'Type d\'œuvre',
|
||||
productTime: 'Date de création',
|
||||
totalReward: 'Solde de récompenses',
|
||||
rewardAmount: 'Montant de la récompense',
|
||||
rewardTime: 'Date de la récompense',
|
||||
reSend: 'Renvoyer',
|
||||
registerSuccessfully: 'Inscription réussie',
|
||||
loginSuccessfully: 'Connexion réussie',
|
||||
passwordResetSuccessfully: 'Mot de passe réinitialisé',
|
||||
rechargeSuccessfully: 'Recharge réussie',
|
||||
avatar: 'Avatar',
|
||||
input: 'Saisir',
|
||||
save: 'Enregistrer',
|
||||
editEmail: 'Modifier l\'email',
|
||||
editEmailSuccessfully: 'Email mis à jour',
|
||||
updateAvatarSuccessfully: 'Avatar mis à jour',
|
||||
balenceLow: 'Solde insuffisant, veuillez recharger',
|
||||
confirm: 'Confirmer',
|
||||
createFailed: 'Échec de génération, solde remboursé',
|
||||
notice: 'Avis',
|
||||
oldPasswordPlaceholder: 'Saisissez l’ancien mot de passe',
|
||||
newpasswordPlaceholder: 'Saisissez le nouveau mot de passe',
|
||||
switchPageTip: 'Une vidéo est en cours de génération ; consultez l’historique des consommations.',
|
||||
loginless: 'Session expirée ! Veuillez vous reconnecter.',
|
||||
createVideo: 'Générer une vidéo (coûte {price} de solde)',
|
||||
ok: 'Confirmer',
|
||||
rechartNotice: 'Instructions de recharge',
|
||||
rechargeNotice1: '1. La recharge est créditée tout de suite. Si rien ne change, actualisez la page.',
|
||||
rechargeNotice2: '2. Les offres limitées sont des promos ; vous pouvez recharger plusieurs fois.',
|
||||
rechargeNotice3: '3. Le solde rechargé n’a pas de limite de durée.',
|
||||
rechargeNotice4: 'Vérifiez l’offre avant d’acheter ; pas de remboursement.',
|
||||
rechargeLeft: 'Solde',
|
||||
dollor: 'USD',
|
||||
isDevelop: 'En cours de développement.',
|
||||
copySuccessfully: 'Copié',
|
||||
copyLink: 'Copier le lien',
|
||||
goPay: 'Aller au paiement',
|
||||
filePreview: 'Aperçu',
|
||||
doSame: 'Créer un équivalent',
|
||||
saveQRCode: 'Enregistrer le QR code',
|
||||
invitationCodePlaceholder: 'Saisissez le code d\'invitation',
|
||||
testRecharge: 'Recharge test',
|
||||
orderNo: 'Numéro de commande',
|
||||
orderNoP: 'Le numéro de commande est obligatoire',
|
||||
emailNotExists: 'Cet email n’est pas inscrit',
|
||||
gearNotExists: 'L’offre choisie n’existe pas ; choisissez une autre.',
|
||||
myProduct: 'Mes œuvres',
|
||||
permissionError: 'Votre total de recharges est {total}, insuffisant pour la prévisualisation.',
|
||||
createTagFailed: 'Échec de génération ; actualisez et réessayez.',
|
||||
loadingText: 'Chargement...',
|
||||
hasMore: 'Tirez pour charger plus',
|
||||
noMore: 'Plus rien',
|
||||
giftAmount: 'Montant crédité',
|
||||
cardNo: 'Numéro de carte',
|
||||
cardName: 'Nom sur la carte',
|
||||
cardNoRequired: 'Saisissez le numéro de carte',
|
||||
cardNameRequired: 'Saisissez le nom sur la carte',
|
||||
rechargeFailed: 'Recharge échouée',
|
||||
vmCardInfo: 'Informations de carte',
|
||||
cardNumber: 'Numéro de carte',
|
||||
cardNumberPlaceholder: 'Saisissez le numéro de carte',
|
||||
cardNumberRequired: 'Saisissez le numéro de carte',
|
||||
cardNumberInvalid: 'Le numéro doit contenir 13 à 19 chiffres',
|
||||
cvc: 'CVC',
|
||||
cvcPlaceholder: 'Saisissez le CVC',
|
||||
cvcRequired: 'Saisissez le CVC',
|
||||
cvcInvalid: 'Le CVC doit faire 3 chiffres',
|
||||
expYear: 'Année d\'expiration',
|
||||
expYearPlaceholder: 'Saisissez l’année (ex. 2027)',
|
||||
expYearRequired: 'Saisissez l’année d\'expiration',
|
||||
expYearInvalid: 'L’année doit faire 4 chiffres',
|
||||
expMonth: 'Mois d\'expiration',
|
||||
expMonthPlaceholder: 'Choisissez le mois',
|
||||
expMonthRequired: 'Choisissez le mois',
|
||||
email: 'Email',
|
||||
emailPlaceholder: 'Saisissez l’email',
|
||||
emailRequired: 'Saisissez l’email',
|
||||
emailInvalid: 'Format d’email invalide',
|
||||
emailMaxLength: 'L’email ne doit pas dépasser 30 caractères',
|
||||
firstName: 'Prénom',
|
||||
firstNamePlaceholder: 'Saisissez le prénom',
|
||||
firstNameRequired: 'Saisissez le prénom',
|
||||
firstNameMaxLength: 'Le prénom ne doit pas dépasser 30 caractères',
|
||||
lastName: 'Nom de famille',
|
||||
lastNamePlaceholder: 'Saisissez le nom de famille',
|
||||
lastNameRequired: 'Saisissez le nom de famille',
|
||||
lastNameMaxLength: 'Le nom ne doit pas dépasser 30 caractères',
|
||||
country: 'Pays',
|
||||
countryPlaceholder: 'Choisissez le pays',
|
||||
countryRequired: 'Choisissez le pays',
|
||||
submit: 'Envoyer',
|
||||
cancel: 'Annuler'
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import route from './route'
|
||||
import common from './common.js'
|
||||
|
||||
export default {
|
||||
route,
|
||||
common
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
index: 'Accueil',
|
||||
imageToImage: 'Déshabiller en un clic',
|
||||
imageToImage2: 'Image vers Image 2',
|
||||
changeFace: 'Changer le visage',
|
||||
changeFaceVideo: 'Changer le visage en vidéo',
|
||||
fastImage: 'Générer une image',
|
||||
fastVideo: 'Générer une vidéo',
|
||||
recharge: 'Recharge rapide',
|
||||
help: 'Centre d\'aide',
|
||||
moneyInvite: 'Invitation avec récompense'
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
export default {
|
||||
image1: 'एक क्लिक में कपड़े उतारें',
|
||||
image2: 'इमेज टू इमेज 2',
|
||||
uploadImage: 'छवि अपलोड करें',
|
||||
uploadImageTip: 'PNG/JPG, अधिकतम 10MB',
|
||||
uploadPlaceholder: 'अपलोड करने के लिए क्लिक करें',
|
||||
selectImageSource: 'छवि स्रोत चुनें',
|
||||
selectTemplate: 'टेम्पलेट चुनें',
|
||||
reselectTemplate: 'टेम्पलेट दोबारा चुनें',
|
||||
noTemplates: 'कोई टेम्पलेट नहीं',
|
||||
tag1: 'टैग प्रकार 1',
|
||||
tag2: 'टैग प्रकार 2',
|
||||
tag3: 'टैग प्रकार 3',
|
||||
generateImage: 'अभी जनरेट करें ({score} बैलेंस खर्च)',
|
||||
generateImageNow: 'अभी जनरेट करें',
|
||||
generateTip: 'सबमिट के बाद "मेरी रचनाएं" में देखें',
|
||||
generateVideo: 'वीडियो जनरेट करें',
|
||||
imageFace: 'छवि में चेहरा बदलें',
|
||||
videoFace: 'वीडियो में चेहरा बदलें',
|
||||
uploadImageFace: 'चेहरे की छवि अपलोड करने के लिए क्लिक करें',
|
||||
uploadTemplate: 'कस्टम टेम्पलेट अपलोड करने के लिए क्लिक करें',
|
||||
textPlaceholder: 'वह छवि बताएं जो आप बनाना चाहते हैं',
|
||||
uploadImageError: 'कृपया एक छवि अपलोड करें',
|
||||
replaceImage: 'छवि बदलें',
|
||||
uploadFaceImageError: 'कृपया चेहरे की छवि अपलोड करें',
|
||||
uploadTemplateError: 'कृपया कस्टम टेम्पलेट अपलोड करें',
|
||||
textError: 'कृपया प्रॉम्प्ट दर्ज करें',
|
||||
textVideoPlaceholder: 'वह वीडियो बताएं जो आप बनाना चाहते हैं',
|
||||
uploadFirstPlaceholder: 'पहला फ्रेम अपलोड करने के लिए क्लिक करें',
|
||||
uploadLastPlaceholder: 'आखिरी फ्रेम अपलोड करने के लिए क्लिक करें',
|
||||
uploadFirstImageError: 'कृपया पहले फ्रेम की छवि अपलोड करें',
|
||||
uploadWaitImageError: 'अपलोड पूरा होने तक प्रतीक्षा करें',
|
||||
saveVideo: 'वीडियो डाउनलोड करें',
|
||||
videoLoadingText: 'वीडियो बन रहा है...',
|
||||
viewVideo: 'वीडियो देखें',
|
||||
changeFacePrompt: 'दूसरी छवि का चेहरा लेकर पहली छवि के चेहरे से बदलें',
|
||||
rechartTip1: 'वॉलेट ट्रांसफर से रिचार्ज करते समय वॉलेट का नेटवर्क जांचें।',
|
||||
rechartTip2: 'रिचार्ज में देरी हो सकती है; 3-5 मिनट बाद रिफ्रेश करें।',
|
||||
walletAddr: 'वॉलेट पता:',
|
||||
fbTitle: 'चेतावनी! यह साइट केवल वयस्कों के लिए है।',
|
||||
fbContent: 'प्रवेश करके मैं पुष्टि करता/करती हूं कि मैं 18 वर्ष या उससे अधिक का हूं',
|
||||
fbCancel: '18 से कम',
|
||||
fbOK: 'मैं 18+ हूं',
|
||||
sorry: 'क्षमा करें!',
|
||||
useLess: 'आप इस साइट का उपयोग नहीं कर सकते...',
|
||||
loginAccount: 'लॉगिन',
|
||||
logout: 'लॉगआउट',
|
||||
userEmailPlaceholder: 'ईमेल या यूजरनेम दर्ज करें',
|
||||
passwordPlaceholder: 'पासवर्ड दर्ज करें',
|
||||
forgetPassword: 'पासवर्ड भूल गए?',
|
||||
register: 'रजिस्टर',
|
||||
login: 'लॉगिन',
|
||||
forgotPassword: 'पासवर्ड भूल गए',
|
||||
registerAccount: 'अकाउंट बनाएं',
|
||||
usernamePlaceholder: 'यूजरनेम दर्ज करें',
|
||||
codePlaceholder: 'वेरिफिकेशन कोड दर्ज करें',
|
||||
confirmPasswordPlaceholder: 'पासवर्ड की पुष्टि करें',
|
||||
backToLogin: 'लॉगिन पर वापस',
|
||||
send: 'भेजें',
|
||||
emailValidPlaceholder: 'वैध ईमेल दर्ज करें',
|
||||
confirmPwdValidMsg: 'पासवर्ड मेल नहीं खाते',
|
||||
editPassword: 'पासवर्ड बदलें',
|
||||
recharge: 'रिचार्ज',
|
||||
myAccount: 'मेरा अकाउंट',
|
||||
moneyInvite: 'इनाम निमंत्रण',
|
||||
rechargeRecord: 'रिचार्ज रिकॉर्ड',
|
||||
resumeRecord: 'खर्च रिकॉर्ड',
|
||||
inviteRecord: 'निमंत्रण रिकॉर्ड',
|
||||
username: 'यूजरनेम',
|
||||
userId: 'यूजर आईडी',
|
||||
accountAmount: 'बैलेंस',
|
||||
editUserInfo: 'जानकारी संपादित करें',
|
||||
contact: 'संपर्क करें',
|
||||
backToUser: 'वापस',
|
||||
moneyTips: 'जब आप दोस्त को रजिस्टर करवाते हैं, उसके रिचार्ज का {rate} हर बार मिलता है।',
|
||||
inviteCode: 'इनवाइट कोड',
|
||||
inviteLink: 'इनवाइट लिंक',
|
||||
saveImage: 'छवि सहेजें',
|
||||
totalAmount: 'कुल रिचार्ज',
|
||||
amount: 'राशि',
|
||||
sendAmount: 'उपहार राशि',
|
||||
rechargeType: 'रिचार्ज तरीका',
|
||||
rechargeTime: 'रिचार्ज समय',
|
||||
emptyText: 'कोई डेटा नहीं',
|
||||
product: 'रचना',
|
||||
resumeAmount: 'खर्च राशि',
|
||||
productType: 'रचना प्रकार',
|
||||
productTime: 'बनाने का समय',
|
||||
totalReward: 'कुल इनाम बैलेंस',
|
||||
rewardAmount: 'इनाम राशि',
|
||||
rewardTime: 'इनाम समय',
|
||||
reSend: 'दोबारा भेजें',
|
||||
registerSuccessfully: 'रजिस्ट्रेशन सफल',
|
||||
loginSuccessfully: 'लॉगिन सफल',
|
||||
passwordResetSuccessfully: 'पासवर्ड रीसेट सफल',
|
||||
rechargeSuccessfully: 'रिचार्ज सफल',
|
||||
avatar: 'अवतार',
|
||||
input: 'दर्ज करें',
|
||||
save: 'सहेजें',
|
||||
editEmail: 'ईमेल बदलें',
|
||||
editEmailSuccessfully: 'ईमेल अपडेट हो गया',
|
||||
updateAvatarSuccessfully: 'अवतार अपडेट हो गया',
|
||||
balenceLow: 'बैलेंस कम है, रिचार्ज करें',
|
||||
confirm: 'पुष्टि करें',
|
||||
createFailed: 'जनरेशन विफल, बैलेंस वापस',
|
||||
notice: 'सूचना',
|
||||
oldPasswordPlaceholder: 'पुराना पासवर्ड दर्ज करें',
|
||||
newpasswordPlaceholder: 'नया पासवर्ड दर्ज करें',
|
||||
switchPageTip: 'वीडियो बन रहा है; निकलकर खर्च रिकॉर्ड देखें।',
|
||||
loginless: 'लॉगिन समाप्त! दोबारा लॉगिन करें।',
|
||||
createVideo: 'वीडियो जनरेट करें ({price} बैलेंस खर्च)',
|
||||
ok: 'पुष्टि करें',
|
||||
rechartNotice: 'रिचार्ज निर्देश',
|
||||
rechargeNotice1: '1. रिचार्ज तुरंत जमा होता है। बदलाव न दिखे तो रिफ्रेश करें।',
|
||||
rechargeNotice2: '2. लिमिटेड पैक प्रचार हैं; आप कई बार रिचार्ज कर सकते हैं।',
|
||||
rechargeNotice3: '3. रिचार्ज की गई राशि की कोई समय सीमा नहीं।',
|
||||
rechargeNotice4: 'खरीदने से पहले पैक देखें; वापसी नहीं होती।',
|
||||
rechargeLeft: 'बैलेंस',
|
||||
dollor: 'USD',
|
||||
isDevelop: 'विकास में है।',
|
||||
copySuccessfully: 'कॉपी हुआ',
|
||||
copyLink: 'लिंक कॉपी करें',
|
||||
goPay: 'भुगतान पर जाएं',
|
||||
filePreview: 'पूर्वावलोकन',
|
||||
doSame: 'इसी तरह बनाएं',
|
||||
saveQRCode: 'QR कोड सहेजें',
|
||||
invitationCodePlaceholder: 'इनवाइट कोड दर्ज करें',
|
||||
testRecharge: 'टेस्ट रिचार्ज',
|
||||
orderNo: 'ऑर्डर नंबर',
|
||||
orderNoP: 'ऑर्डर नंबर खाली नहीं हो सकता',
|
||||
emailNotExists: 'यह ईमेल रजिस्टर नहीं है',
|
||||
gearNotExists: 'चुना गया रिचार्ज प्लान मौजूद नहीं; दूसरा चुनें।',
|
||||
myProduct: 'मेरी रचनाएं',
|
||||
permissionError: 'आपका कुल रिचार्ज {total} है, प्रीव्यू के लिए पर्याप्त नहीं।',
|
||||
createTagFailed: 'जनरेशन विफल; रिफ्रेश करके दोबारा कोशिश करें।',
|
||||
loadingText: 'लोड हो रहा है...',
|
||||
hasMore: 'ऊपर खींचें और अधिक लोड करें',
|
||||
noMore: 'और नहीं',
|
||||
giftAmount: 'जमा राशि',
|
||||
cardNo: 'कार्ड नंबर',
|
||||
cardName: 'कार्डधारक का नाम',
|
||||
cardNoRequired: 'कार्ड नंबर दर्ज करें',
|
||||
cardNameRequired: 'कार्डधारक का नाम दर्ज करें',
|
||||
rechargeFailed: 'रिचार्ज विफल',
|
||||
vmCardInfo: 'कार्ड जानकारी',
|
||||
cardNumber: 'कार्ड नंबर',
|
||||
cardNumberPlaceholder: 'कार्ड नंबर दर्ज करें',
|
||||
cardNumberRequired: 'कार्ड नंबर दर्ज करें',
|
||||
cardNumberInvalid: 'कार्ड नंबर 13-19 अंकों का होना चाहिए',
|
||||
cvc: 'CVC',
|
||||
cvcPlaceholder: 'CVC दर्ज करें',
|
||||
cvcRequired: 'CVC दर्ज करें',
|
||||
cvcInvalid: 'CVC 3 अंकों का होना चाहिए',
|
||||
expYear: 'समाप्ति वर्ष',
|
||||
expYearPlaceholder: 'वर्ष दर्ज करें (जैसे 2027)',
|
||||
expYearRequired: 'समाप्ति वर्ष दर्ज करें',
|
||||
expYearInvalid: 'वर्ष 4 अंकों का होना चाहिए',
|
||||
expMonth: 'समाप्ति माह',
|
||||
expMonthPlaceholder: 'माह चुनें',
|
||||
expMonthRequired: 'माह चुनें',
|
||||
email: 'ईमेल',
|
||||
emailPlaceholder: 'ईमेल दर्ज करें',
|
||||
emailRequired: 'ईमेल दर्ज करें',
|
||||
emailInvalid: 'ईमेल फॉर्मेट गलत',
|
||||
emailMaxLength: 'ईमेल 30 अक्षर से अधिक नहीं',
|
||||
firstName: 'पहला नाम',
|
||||
firstNamePlaceholder: 'पहला नाम दर्ज करें',
|
||||
firstNameRequired: 'पहला नाम दर्ज करें',
|
||||
firstNameMaxLength: 'पहला नाम 30 अक्षर से अधिक नहीं',
|
||||
lastName: 'उपनाम',
|
||||
lastNamePlaceholder: 'उपनाम दर्ज करें',
|
||||
lastNameRequired: 'उपनाम दर्ज करें',
|
||||
lastNameMaxLength: 'उपनाम 30 अक्षर से अधिक नहीं',
|
||||
country: 'देश',
|
||||
countryPlaceholder: 'देश चुनें',
|
||||
countryRequired: 'देश चुनें',
|
||||
submit: 'भेजें',
|
||||
cancel: 'रद्द करें'
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import route from './route'
|
||||
import common from './common.js'
|
||||
|
||||
export default {
|
||||
route,
|
||||
common
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
index: 'होम',
|
||||
imageToImage: 'एक क्लिक में कपड़े उतारें',
|
||||
imageToImage2: 'इमेज टू इमेज 2',
|
||||
changeFace: 'चेहरा बदलें',
|
||||
changeFaceVideo: 'वीडियो में चेहरा बदलें',
|
||||
fastImage: 'छवि जनरेट करें',
|
||||
fastVideo: 'वीडियो जनरेट करें',
|
||||
recharge: 'त्वरित रिचार्ज',
|
||||
help: 'सहायता केंद्र',
|
||||
moneyInvite: 'इनाम निमंत्रण'
|
||||
}
|
||||
|
|
@ -2,40 +2,16 @@ import { createI18n } from 'vue-i18n'
|
|||
import Cookies from 'js-cookie'
|
||||
import zh_HK from '@/lang/zh_HK/index.js'
|
||||
import en_US from '@/lang/en_US/index.js'
|
||||
import es_ES from '@/lang/es_ES/index.js'
|
||||
import pt_BR from '@/lang/pt_BR/index.js'
|
||||
import hi_IN from '@/lang/hi_IN/index.js'
|
||||
import ru_RU from '@/lang/ru_RU/index.js'
|
||||
import ar_SA from '@/lang/ar_SA/index.js'
|
||||
import fr_FR from '@/lang/fr_FR/index.js'
|
||||
|
||||
let locale = Cookies.get('language') || 'en_US'
|
||||
|
||||
/** 各语言在界面上的显示名称 */
|
||||
export const LOCALE_NAMES = {
|
||||
zh_HK: '繁体中文',
|
||||
en_US: 'English',
|
||||
es_ES: 'Español',
|
||||
pt_BR: 'Português',
|
||||
hi_IN: 'हिन्दी',
|
||||
ru_RU: 'Русский',
|
||||
ar_SA: 'العربية',
|
||||
fr_FR: 'Français'
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
globalInjection: true,
|
||||
locale,
|
||||
messages: {
|
||||
globalInjection: true,
|
||||
locale,
|
||||
messages: {
|
||||
zh_HK,
|
||||
en_US,
|
||||
es_ES,
|
||||
pt_BR,
|
||||
hi_IN,
|
||||
ru_RU,
|
||||
ar_SA,
|
||||
fr_FR
|
||||
}
|
||||
en_US
|
||||
}
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
|
|
|||
|
|
@ -1,179 +0,0 @@
|
|||
export default {
|
||||
image1: 'Despir em um clique',
|
||||
image2: 'Imagem para Imagem 2',
|
||||
uploadImage: 'Enviar imagem',
|
||||
uploadImageTip: 'PNG/JPG, máx. 10MB',
|
||||
uploadPlaceholder: 'Clique para enviar imagem',
|
||||
selectImageSource: 'Selecionar origem da imagem',
|
||||
selectTemplate: 'Selecionar modelo',
|
||||
reselectTemplate: 'Selecionar outro modelo',
|
||||
noTemplates: 'Sem modelos',
|
||||
tag1: 'Tipo de tag 1',
|
||||
tag2: 'Tipo de tag 2',
|
||||
tag3: 'Tipo de tag 3',
|
||||
generateImage: 'Gerar agora (usa {score} de saldo)',
|
||||
generateImageNow: 'Gerar agora',
|
||||
generateTip: 'Após enviar, veja em "Minhas obras"',
|
||||
generateVideo: 'Gerar vídeo',
|
||||
imageFace: 'Trocar rosto em imagem',
|
||||
videoFace: 'Trocar rosto em vídeo',
|
||||
uploadImageFace: 'Clique para enviar imagem do rosto',
|
||||
uploadTemplate: 'Clique para enviar modelo personalizado',
|
||||
textPlaceholder: 'Descreva a imagem que deseja gerar',
|
||||
uploadImageError: 'Envie uma imagem',
|
||||
replaceImage: 'Substituir imagem',
|
||||
uploadFaceImageError: 'Envie uma imagem do rosto',
|
||||
uploadTemplateError: 'Envie um modelo personalizado',
|
||||
textError: 'Digite o texto de indicação',
|
||||
textVideoPlaceholder: 'Descreva o vídeo que deseja gerar',
|
||||
uploadFirstPlaceholder: 'Clique para enviar primeiro frame',
|
||||
uploadLastPlaceholder: 'Clique para enviar último frame',
|
||||
uploadFirstImageError: 'Envie a imagem do primeiro frame',
|
||||
uploadWaitImageError: 'Aguarde o envio terminar',
|
||||
saveVideo: 'Baixar vídeo',
|
||||
videoLoadingText: 'Gerando vídeo...',
|
||||
viewVideo: 'Ver vídeo',
|
||||
changeFacePrompt: 'Extrair o rosto da segunda imagem e substituir na primeira',
|
||||
rechartTip1: 'Ao recarregar por carteira, confirme a rede do carteira.',
|
||||
rechartTip2: 'A recarga pode atrasar; aguarde 3-5 minutos antes de atualizar.',
|
||||
walletAddr: 'Endereço da carteira:',
|
||||
fbTitle: 'Aviso: este site é apenas para maiores de 18 anos.',
|
||||
fbContent: 'Ao entrar confirmo que tenho 18 anos ou mais',
|
||||
fbCancel: 'Menor de 18',
|
||||
fbOK: 'Tenho 18 ou mais',
|
||||
sorry: 'Desculpe!',
|
||||
useLess: 'Você não pode usar este site...',
|
||||
loginAccount: 'Entrar',
|
||||
logout: 'Sair',
|
||||
userEmailPlaceholder: 'Digite e-mail ou usuário',
|
||||
passwordPlaceholder: 'Digite a senha',
|
||||
forgetPassword: 'Esqueceu a senha?',
|
||||
register: 'Cadastrar',
|
||||
login: 'Entrar',
|
||||
forgotPassword: 'Esqueci a senha',
|
||||
registerAccount: 'Criar conta',
|
||||
usernamePlaceholder: 'Digite o usuário',
|
||||
codePlaceholder: 'Digite o código de verificação',
|
||||
confirmPasswordPlaceholder: 'Confirme a senha',
|
||||
backToLogin: 'Voltar ao login',
|
||||
send: 'Enviar',
|
||||
emailValidPlaceholder: 'Digite um e-mail válido',
|
||||
confirmPwdValidMsg: 'As senhas não coincidem',
|
||||
editPassword: 'Alterar senha',
|
||||
recharge: 'Recarregar',
|
||||
myAccount: 'Minha conta',
|
||||
moneyInvite: 'Convite com recompensa',
|
||||
rechargeRecord: 'Histórico de recargas',
|
||||
resumeRecord: 'Histórico de consumo',
|
||||
inviteRecord: 'Histórico de convites',
|
||||
username: 'Usuário',
|
||||
userId: 'ID do usuário',
|
||||
accountAmount: 'Saldo',
|
||||
editUserInfo: 'Editar dados',
|
||||
contact: 'Contato',
|
||||
backToUser: 'Voltar',
|
||||
moneyTips: 'Ao convidar um amigo, você ganha {rate} do valor que ele recarregar.',
|
||||
inviteCode: 'Código de convite',
|
||||
inviteLink: 'Link de convite',
|
||||
saveImage: 'Salvar imagem',
|
||||
totalAmount: 'Total recarregado',
|
||||
amount: 'Valor',
|
||||
sendAmount: 'Valor de brinde',
|
||||
rechargeType: 'Forma de recarga',
|
||||
rechargeTime: 'Data da recarga',
|
||||
emptyText: 'Sem dados',
|
||||
product: 'Obra',
|
||||
resumeAmount: 'Valor consumido',
|
||||
productType: 'Tipo de obra',
|
||||
productTime: 'Data de criação',
|
||||
totalReward: 'Saldo de recompensas',
|
||||
rewardAmount: 'Valor da recompensa',
|
||||
rewardTime: 'Data da recompensa',
|
||||
reSend: 'Reenviar',
|
||||
registerSuccessfully: 'Cadastro concluído',
|
||||
loginSuccessfully: 'Login realizado',
|
||||
passwordResetSuccessfully: 'Senha redefinida',
|
||||
rechargeSuccessfully: 'Recarga concluída',
|
||||
avatar: 'Avatar',
|
||||
input: 'Digite',
|
||||
save: 'Salvar',
|
||||
editEmail: 'Alterar e-mail',
|
||||
editEmailSuccessfully: 'E-mail atualizado',
|
||||
updateAvatarSuccessfully: 'Avatar atualizado',
|
||||
balenceLow: 'Saldo insuficiente, recarregue',
|
||||
confirm: 'Confirmar',
|
||||
createFailed: 'Falha na geração, saldo devolvido',
|
||||
notice: 'Aviso',
|
||||
oldPasswordPlaceholder: 'Digite a senha antiga',
|
||||
newpasswordPlaceholder: 'Digite a nova senha',
|
||||
switchPageTip: 'O vídeo está sendo gerado; saia e veja o histórico de consumo.',
|
||||
loginless: 'Sessão expirada; faça login novamente.',
|
||||
createVideo: 'Gerar vídeo (usa {price} de saldo)',
|
||||
ok: 'Confirmar',
|
||||
rechartNotice: 'Instruções de recarga',
|
||||
rechargeNotice1: '1. A recarga é creditada na hora. Se não mudar, atualize a página.',
|
||||
rechargeNotice2: '2. Pacotes por tempo limitado são promoções; você pode recarregar várias vezes.',
|
||||
rechargeNotice3: '3. O saldo recarregado não tem prazo.',
|
||||
rechargeNotice4: 'Confira o pacote antes de comprar; não há reembolso.',
|
||||
rechargeLeft: 'Saldo',
|
||||
dollor: 'USD',
|
||||
isDevelop: 'Em desenvolvimento.',
|
||||
copySuccessfully: 'Copiado',
|
||||
copyLink: 'Copiar link',
|
||||
goPay: 'Ir para pagamento',
|
||||
filePreview: 'Visualizar',
|
||||
doSame: 'Fazer igual',
|
||||
saveQRCode: 'Salvar código QR',
|
||||
invitationCodePlaceholder: 'Digite o código de convite',
|
||||
testRecharge: 'Recarga de teste',
|
||||
orderNo: 'Número do pedido',
|
||||
orderNoP: 'O número do pedido é obrigatório',
|
||||
emailNotExists: 'O e-mail não está cadastrado',
|
||||
gearNotExists: 'O plano de recarga não existe; escolha outro.',
|
||||
myProduct: 'Minhas obras',
|
||||
permissionError: 'Sua recarga acumulada é {total}, não atende para visualizar.',
|
||||
createTagFailed: 'Falha na geração; atualize e tente de novo.',
|
||||
loadingText: 'Carregando...',
|
||||
hasMore: 'Deslize para mais',
|
||||
noMore: 'Não há mais',
|
||||
giftAmount: 'Valor creditado',
|
||||
cardNo: 'Número do cartão',
|
||||
cardName: 'Nome no cartão',
|
||||
cardNoRequired: 'Digite o número do cartão',
|
||||
cardNameRequired: 'Digite o nome no cartão',
|
||||
rechargeFailed: 'Recarga falhou',
|
||||
vmCardInfo: 'Dados do cartão',
|
||||
cardNumber: 'Número do cartão',
|
||||
cardNumberPlaceholder: 'Digite o número do cartão',
|
||||
cardNumberRequired: 'Digite o número do cartão',
|
||||
cardNumberInvalid: 'O número deve ter 13-19 dígitos',
|
||||
cvc: 'CVC',
|
||||
cvcPlaceholder: 'Digite o CVC',
|
||||
cvcRequired: 'Digite o CVC',
|
||||
cvcInvalid: 'CVC deve ter 3 dígitos',
|
||||
expYear: 'Ano de validade',
|
||||
expYearPlaceholder: 'Digite o ano (ex.: 2027)',
|
||||
expYearRequired: 'Digite o ano de validade',
|
||||
expYearInvalid: 'O ano deve ter 4 dígitos',
|
||||
expMonth: 'Mês de validade',
|
||||
expMonthPlaceholder: 'Selecione o mês',
|
||||
expMonthRequired: 'Selecione o mês',
|
||||
email: 'E-mail',
|
||||
emailPlaceholder: 'Digite o e-mail',
|
||||
emailRequired: 'Digite o e-mail',
|
||||
emailInvalid: 'Formato de e-mail inválido',
|
||||
emailMaxLength: 'Máx. 30 caracteres',
|
||||
firstName: 'Nome',
|
||||
firstNamePlaceholder: 'Digite o nome',
|
||||
firstNameRequired: 'Digite o nome',
|
||||
firstNameMaxLength: 'Máx. 30 caracteres',
|
||||
lastName: 'Sobrenome',
|
||||
lastNamePlaceholder: 'Digite o sobrenome',
|
||||
lastNameRequired: 'Digite o sobrenome',
|
||||
lastNameMaxLength: 'Máx. 30 caracteres',
|
||||
country: 'País',
|
||||
countryPlaceholder: 'Selecione o país',
|
||||
countryRequired: 'Selecione o país',
|
||||
submit: 'Enviar',
|
||||
cancel: 'Cancelar'
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import route from './route'
|
||||
import common from './common.js'
|
||||
|
||||
export default {
|
||||
route,
|
||||
common
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
index: 'Início',
|
||||
imageToImage: 'Despir em um clique',
|
||||
imageToImage2: 'Imagem para Imagem 2',
|
||||
changeFace: 'Trocar rosto',
|
||||
changeFaceVideo: 'Trocar rosto em vídeo',
|
||||
fastImage: 'Gerar imagem',
|
||||
fastVideo: 'Gerar vídeo',
|
||||
recharge: 'Recarga rápida',
|
||||
help: 'Central de ajuda',
|
||||
moneyInvite: 'Convite com recompensa'
|
||||
}
|
||||
|
|
@ -1,179 +0,0 @@
|
|||
export default {
|
||||
image1: 'Раздеть в один клик',
|
||||
image2: 'Изображение в изображение 2',
|
||||
uploadImage: 'Загрузить изображение',
|
||||
uploadImageTip: 'PNG/JPG, макс. 10 МБ',
|
||||
uploadPlaceholder: 'Нажмите, чтобы загрузить',
|
||||
selectImageSource: 'Выберите источник изображения',
|
||||
selectTemplate: 'Выберите шаблон',
|
||||
reselectTemplate: 'Выбрать шаблон заново',
|
||||
noTemplates: 'Нет шаблонов',
|
||||
tag1: 'Тип метки 1',
|
||||
tag2: 'Тип метки 2',
|
||||
tag3: 'Тип метки 3',
|
||||
generateImage: 'Создать сейчас (списание {score} с баланса)',
|
||||
generateImageNow: 'Создать сейчас',
|
||||
generateTip: 'После отправки смотрите в «Мои работы»',
|
||||
generateVideo: 'Создать видео',
|
||||
imageFace: 'Заменить лицо на изображении',
|
||||
videoFace: 'Заменить лицо в видео',
|
||||
uploadImageFace: 'Нажмите, чтобы загрузить фото лица',
|
||||
uploadTemplate: 'Нажмите, чтобы загрузить свой шаблон',
|
||||
textPlaceholder: 'Опишите изображение, которое хотите получить',
|
||||
uploadImageError: 'Загрузите изображение',
|
||||
replaceImage: 'Заменить изображение',
|
||||
uploadFaceImageError: 'Загрузите фото лица',
|
||||
uploadTemplateError: 'Загрузите свой шаблон',
|
||||
textError: 'Введите текст подсказки',
|
||||
textVideoPlaceholder: 'Опишите видео, которое хотите получить',
|
||||
uploadFirstPlaceholder: 'Нажмите, чтобы загрузить первый кадр',
|
||||
uploadLastPlaceholder: 'Нажмите, чтобы загрузить последний кадр',
|
||||
uploadFirstImageError: 'Загрузите изображение первого кадра',
|
||||
uploadWaitImageError: 'Дождитесь окончания загрузки',
|
||||
saveVideo: 'Скачать видео',
|
||||
videoLoadingText: 'Создание видео...',
|
||||
viewVideo: 'Смотреть видео',
|
||||
changeFacePrompt: 'Взять лицо со второй картинки и заменить им лицо на первой',
|
||||
rechartTip1: 'При пополнении через кошелёк проверьте сеть кошелька.',
|
||||
rechartTip2: 'Зачисление может задерживаться; подождите 3–5 минут и обновите.',
|
||||
walletAddr: 'Адрес кошелька:',
|
||||
fbTitle: 'Внимание! Сайт только для взрослых!',
|
||||
fbContent: 'Входя, я подтверждаю, что мне 18 лет или больше',
|
||||
fbCancel: 'Мне нет 18',
|
||||
fbOK: 'Мне есть 18',
|
||||
sorry: 'Извините!',
|
||||
useLess: 'Вам запрещено пользоваться этим сайтом...',
|
||||
loginAccount: 'Вход',
|
||||
logout: 'Выйти',
|
||||
userEmailPlaceholder: 'Введите email или логин',
|
||||
passwordPlaceholder: 'Введите пароль',
|
||||
forgetPassword: 'Забыли пароль?',
|
||||
register: 'Регистрация',
|
||||
login: 'Войти',
|
||||
forgotPassword: 'Забыл пароль',
|
||||
registerAccount: 'Создать аккаунт',
|
||||
usernamePlaceholder: 'Введите имя пользователя',
|
||||
codePlaceholder: 'Введите код подтверждения',
|
||||
confirmPasswordPlaceholder: 'Подтвердите пароль',
|
||||
backToLogin: 'Вернуться к входу',
|
||||
send: 'Отправить',
|
||||
emailValidPlaceholder: 'Введите корректный email',
|
||||
confirmPwdValidMsg: 'Пароли не совпадают',
|
||||
editPassword: 'Изменить пароль',
|
||||
recharge: 'Пополнить',
|
||||
myAccount: 'Мой аккаунт',
|
||||
moneyInvite: 'Приглашение с наградой',
|
||||
rechargeRecord: 'История пополнений',
|
||||
resumeRecord: 'История списаний',
|
||||
inviteRecord: 'История приглашений',
|
||||
username: 'Имя пользователя',
|
||||
userId: 'ID пользователя',
|
||||
accountAmount: 'Баланс',
|
||||
editUserInfo: 'Редактировать данные',
|
||||
contact: 'Связаться с нами',
|
||||
backToUser: 'Назад',
|
||||
moneyTips: 'При регистрации по вашей ссылке вы получаете {rate} от каждой его пополнения.',
|
||||
inviteCode: 'Код приглашения',
|
||||
inviteLink: 'Ссылка приглашения',
|
||||
saveImage: 'Сохранить изображение',
|
||||
totalAmount: 'Всего пополнено',
|
||||
amount: 'Сумма',
|
||||
sendAmount: 'Сумма бонуса',
|
||||
rechargeType: 'Способ пополнения',
|
||||
rechargeTime: 'Время пополнения',
|
||||
emptyText: 'Нет данных',
|
||||
product: 'Работа',
|
||||
resumeAmount: 'Списано',
|
||||
productType: 'Тип работы',
|
||||
productTime: 'Дата создания',
|
||||
totalReward: 'Баланс наград',
|
||||
rewardAmount: 'Сумма награды',
|
||||
rewardTime: 'Время награды',
|
||||
reSend: 'Отправить снова',
|
||||
registerSuccessfully: 'Регистрация выполнена',
|
||||
loginSuccessfully: 'Вход выполнен',
|
||||
passwordResetSuccessfully: 'Пароль сброшен',
|
||||
rechargeSuccessfully: 'Пополнение выполнено',
|
||||
avatar: 'Аватар',
|
||||
input: 'Введите',
|
||||
save: 'Сохранить',
|
||||
editEmail: 'Изменить email',
|
||||
editEmailSuccessfully: 'Email обновлён',
|
||||
updateAvatarSuccessfully: 'Аватар обновлён',
|
||||
balenceLow: 'Недостаточно средств, пополните баланс',
|
||||
confirm: 'Подтвердить',
|
||||
createFailed: 'Ошибка создания, средства возвращены',
|
||||
notice: 'Уведомление',
|
||||
oldPasswordPlaceholder: 'Введите старый пароль',
|
||||
newpasswordPlaceholder: 'Введите новый пароль',
|
||||
switchPageTip: 'Видео создаётся; выйдите и проверьте историю списаний.',
|
||||
loginless: 'Сессия истекла. Войдите снова.',
|
||||
createVideo: 'Создать видео (списание {price} с баланса)',
|
||||
ok: 'Подтвердить',
|
||||
rechartNotice: 'Правила пополнения',
|
||||
rechargeNotice1: '1. Средства зачисляются сразу. Если не изменилось — обновите страницу.',
|
||||
rechargeNotice2: '2. Акционные пакеты проводятся периодически; можно пополнять несколько раз.',
|
||||
rechargeNotice3: '3. Пополненный баланс не имеет срока действия.',
|
||||
rechargeNotice4: 'Перед покупкой ознакомьтесь с пакетом; возврат не предусмотрен.',
|
||||
rechargeLeft: 'Баланс',
|
||||
dollor: 'USD',
|
||||
isDevelop: 'В разработке.',
|
||||
copySuccessfully: 'Скопировано',
|
||||
copyLink: 'Копировать ссылку',
|
||||
goPay: 'Перейти к оплате',
|
||||
filePreview: 'Предпросмотр',
|
||||
doSame: 'Сделать похожее',
|
||||
saveQRCode: 'Сохранить QR-код',
|
||||
invitationCodePlaceholder: 'Введите код приглашения',
|
||||
testRecharge: 'Тестовое пополнение',
|
||||
orderNo: 'Номер заказа',
|
||||
orderNoP: 'Номер заказа обязателен',
|
||||
emailNotExists: 'Этот email не зарегистрирован',
|
||||
gearNotExists: 'Выбранный тариф отсутствует; выберите другой.',
|
||||
myProduct: 'Мои работы',
|
||||
permissionError: 'Ваше суммарное пополнение {total}, недостаточно для просмотра.',
|
||||
createTagFailed: 'Ошибка создания; обновите страницу и повторите.',
|
||||
loadingText: 'Загрузка...',
|
||||
hasMore: 'Потяните вверх для подгрузки',
|
||||
noMore: 'Больше нет',
|
||||
giftAmount: 'Зачисленная сумма',
|
||||
cardNo: 'Номер карты',
|
||||
cardName: 'Имя владельца',
|
||||
cardNoRequired: 'Введите номер карты',
|
||||
cardNameRequired: 'Введите имя владельца',
|
||||
rechargeFailed: 'Ошибка пополнения',
|
||||
vmCardInfo: 'Данные карты',
|
||||
cardNumber: 'Номер карты',
|
||||
cardNumberPlaceholder: 'Введите номер карты',
|
||||
cardNumberRequired: 'Введите номер карты',
|
||||
cardNumberInvalid: 'Номер карты должен быть из 13–19 цифр',
|
||||
cvc: 'CVC',
|
||||
cvcPlaceholder: 'Введите CVC',
|
||||
cvcRequired: 'Введите CVC',
|
||||
cvcInvalid: 'CVC должен быть из 3 цифр',
|
||||
expYear: 'Год срока действия',
|
||||
expYearPlaceholder: 'Введите год (например 2027)',
|
||||
expYearRequired: 'Введите год',
|
||||
expYearInvalid: 'Год должен быть из 4 цифр',
|
||||
expMonth: 'Месяц срока действия',
|
||||
expMonthPlaceholder: 'Выберите месяц',
|
||||
expMonthRequired: 'Выберите месяц',
|
||||
email: 'Email',
|
||||
emailPlaceholder: 'Введите email',
|
||||
emailRequired: 'Введите email',
|
||||
emailInvalid: 'Некорректный email',
|
||||
emailMaxLength: 'Email не более 30 символов',
|
||||
firstName: 'Имя',
|
||||
firstNamePlaceholder: 'Введите имя',
|
||||
firstNameRequired: 'Введите имя',
|
||||
firstNameMaxLength: 'Имя не более 30 символов',
|
||||
lastName: 'Фамилия',
|
||||
lastNamePlaceholder: 'Введите фамилию',
|
||||
lastNameRequired: 'Введите фамилию',
|
||||
lastNameMaxLength: 'Фамилия не более 30 символов',
|
||||
country: 'Страна',
|
||||
countryPlaceholder: 'Выберите страну',
|
||||
countryRequired: 'Выберите страну',
|
||||
submit: 'Отправить',
|
||||
cancel: 'Отмена'
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
import route from './route'
|
||||
import common from './common.js'
|
||||
|
||||
export default {
|
||||
route,
|
||||
common
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export default {
|
||||
index: 'Главная',
|
||||
imageToImage: 'Раздеть в один клик',
|
||||
imageToImage2: 'Изображение в изображение 2',
|
||||
changeFace: 'Заменить лицо',
|
||||
changeFaceVideo: 'Заменить лицо в видео',
|
||||
fastImage: 'Создать изображение',
|
||||
fastVideo: 'Создать видео',
|
||||
recharge: 'Быстрая пополнение',
|
||||
help: 'Центр помощи',
|
||||
moneyInvite: 'Приглашение с наградой'
|
||||
}
|
||||
|
|
@ -21,7 +21,6 @@ export default {
|
|||
uploadTemplate: '點擊上傳自定義模板',
|
||||
textPlaceholder: '請描述你想生成的圖片',
|
||||
uploadImageError: '請上傳圖片',
|
||||
replaceImage: '替換圖片',
|
||||
uploadFaceImageError: '請上傳人臉圖片',
|
||||
uploadTemplateError: '請上傳自定義模板',
|
||||
textError: '請輸入提示詞',
|
||||
|
|
@ -145,14 +144,6 @@ export default {
|
|||
cardNoRequired: '請輸入銀行卡號',
|
||||
cardNameRequired: '請輸入銀行卡姓名',
|
||||
rechargeFailed: '充值失敗',
|
||||
// 模型选择
|
||||
selectModel: '選擇模型',
|
||||
seedance20: 'Seedance 2.0',
|
||||
seedance20Fast: 'Seedance 2.0 Fast',
|
||||
// 富文本编辑器
|
||||
insertImage: '插入圖片',
|
||||
mentionImage: '引用圖片',
|
||||
noImageToMention: '暫無可引用的圖片',
|
||||
// VM支付相關
|
||||
vmCardInfo: '信用卡信息',
|
||||
cardNumber: '信用卡卡號',
|
||||
|
|
@ -186,9 +177,6 @@ export default {
|
|||
country: '國家',
|
||||
countryPlaceholder: '請選擇國家',
|
||||
countryRequired: '請選擇國家',
|
||||
videoGen: '視頻生成',
|
||||
uploadFirstImage: '上傳首圖',
|
||||
insertImage: '插入圖片',
|
||||
submit: '提交',
|
||||
cancel: '取消'
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ export default {
|
|||
changeFaceVideo: '視頻換臉',
|
||||
fastImage: '快捷生圖',
|
||||
fastVideo: '快捷生視頻',
|
||||
videoGen: '視頻生成',
|
||||
recharge: '快速充值',
|
||||
help: '幫助中心',
|
||||
moneyInvite: '有獎邀請'
|
||||
|
|
|
|||
|
|
@ -29,12 +29,11 @@
|
|||
:title="$t('common.moneyInvite')">
|
||||
<Money />
|
||||
</a-tab-pane>
|
||||
<!-- 隐藏快速充值入口 -->
|
||||
<!-- <a-tab-pane
|
||||
<a-tab-pane
|
||||
key="recharge"
|
||||
:title="$t('common.rechargeRecord')">
|
||||
<RechargeRecord />
|
||||
</a-tab-pane> -->
|
||||
</a-tab-pane>
|
||||
<a-tab-pane
|
||||
key="resume"
|
||||
:title="$t('common.myProduct')">
|
||||
|
|
@ -68,6 +67,7 @@ import { mapGetters } from 'vuex'
|
|||
import i18n from '@/lang/i18n'
|
||||
import Money from './Money.vue'
|
||||
import UserAccount from './UserAccount.vue'
|
||||
import RechargeRecord from './RechargeRecord.vue'
|
||||
import ResumeRecord from './ResumeRecord.vue'
|
||||
import RewardRecord from './RewardRecord.vue'
|
||||
|
||||
|
|
@ -93,6 +93,7 @@ export default {
|
|||
Register,
|
||||
Money,
|
||||
UserAccount,
|
||||
RechargeRecord,
|
||||
ResumeRecord,
|
||||
RewardRecord
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,16 +33,12 @@
|
|||
<div class="right-menu-item language">
|
||||
<a-dropdown @select="handleSelect">
|
||||
<mf-button type="text">
|
||||
{{ localeName }}
|
||||
{{ lang == 'zh_HK' ? '繁体中文' : 'English' }}
|
||||
<icon-down />
|
||||
</mf-button>
|
||||
<template #content>
|
||||
<a-doption
|
||||
v-for="(name, code) in localeNames"
|
||||
:key="code"
|
||||
:value="code">
|
||||
{{ name }}
|
||||
</a-doption>
|
||||
<a-doption value="zh_HK">繁体中文</a-doption>
|
||||
<a-doption value="en_US">English</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
|
|
@ -97,7 +93,7 @@ import { mapGetters, mapState } from 'vuex'
|
|||
import cloneDeep from 'lodash-es/cloneDeep'
|
||||
import { constantRoutes } from '@/router/index.js'
|
||||
import Login from './Login.vue'
|
||||
import i18n, { LOCALE_NAMES } from '@/lang/i18n'
|
||||
import i18n from '@/lang/i18n'
|
||||
import User from './User.vue'
|
||||
|
||||
export default {
|
||||
|
|
@ -126,12 +122,6 @@ export default {
|
|||
demoEnv() {
|
||||
return import.meta.env.MODE === 'demo'
|
||||
},
|
||||
localeNames() {
|
||||
return LOCALE_NAMES
|
||||
},
|
||||
localeName() {
|
||||
return LOCALE_NAMES[this.lang] || 'English'
|
||||
},
|
||||
...mapGetters([
|
||||
'theme',
|
||||
'permission_routes',
|
||||
|
|
|
|||
|
|
@ -9,11 +9,9 @@ import router from './router'
|
|||
|
||||
import '@/assets/styles/base.less'
|
||||
|
||||
// Quill 样式 - 临时注释避免 source map 文件缺失导致的构建错误
|
||||
// 如果后续需要使用 Quill 富文本编辑器,可取消注释
|
||||
// import '@/assets/styles/quill.bubble.css'
|
||||
// import '@/assets/styles/quill.core.css'
|
||||
// import '@/assets/styles/quill.snow.css'
|
||||
import '@/assets/styles/quill.bubble.css'
|
||||
import '@/assets/styles/quill.core.css'
|
||||
import '@/assets/styles/quill.snow.css'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(router)
|
||||
|
|
|
|||
|
|
@ -69,47 +69,49 @@ export const constantRoutes = [{
|
|||
permission: "pass",
|
||||
icon: 'btn_tst'
|
||||
}
|
||||
}, {
|
||||
path: 'image-to-image?type=2',
|
||||
name: 'image-to-image2',
|
||||
component: () => import('@/views/Image.vue'),
|
||||
meta: {
|
||||
title: 'imageToImage2',
|
||||
menuItem: true,
|
||||
permission: "pass",
|
||||
icon: 'btn_tst'
|
||||
}
|
||||
}, {
|
||||
path: 'change-face',
|
||||
name: 'change-face',
|
||||
component: () => import('@/views/ChangeFace.vue'),
|
||||
meta: {
|
||||
title: 'changeFace',
|
||||
menuItem: true,
|
||||
permission: "pass",
|
||||
icon: 'btn_yjhl'
|
||||
}
|
||||
}, {
|
||||
path: 'change-face-video',
|
||||
name: 'change-face-video',
|
||||
component: () => import('@/views/ChangeFace.vue'),
|
||||
meta: {
|
||||
title: 'changeFaceVideo',
|
||||
menuItem: true,
|
||||
permission: "pass",
|
||||
icon: 'btn_yjhl'
|
||||
}
|
||||
}, {
|
||||
path: 'fast-image',
|
||||
name: 'fast-image',
|
||||
component: () => import('@/views/FastImage.vue'),
|
||||
meta: {
|
||||
title: 'fastImage',
|
||||
menuItem: true,
|
||||
permission: "pass",
|
||||
icon: 'btn_kjst'
|
||||
}
|
||||
}, {
|
||||
},
|
||||
// {
|
||||
// path: 'image-to-image?type=2',
|
||||
// name: 'image-to-image2',
|
||||
// component: () => import('@/views/Image.vue'),
|
||||
// meta: {
|
||||
// title: 'imageToImage2',
|
||||
// menuItem: true,
|
||||
// permission: "pass",
|
||||
// icon: 'btn_tst'
|
||||
// }
|
||||
// }, {
|
||||
// path: 'change-face',
|
||||
// name: 'change-face',
|
||||
// component: () => import('@/views/ChangeFace.vue'),
|
||||
// meta: {
|
||||
// title: 'changeFace',
|
||||
// menuItem: true,
|
||||
// permission: "pass",
|
||||
// icon: 'btn_yjhl'
|
||||
// }
|
||||
// }, {
|
||||
// path: 'change-face-video',
|
||||
// name: 'change-face-video',
|
||||
// component: () => import('@/views/ChangeFace.vue'),
|
||||
// meta: {
|
||||
// title: 'changeFaceVideo',
|
||||
// menuItem: true,
|
||||
// permission: "pass",
|
||||
// icon: 'btn_yjhl'
|
||||
// }
|
||||
// }, {
|
||||
// path: 'fast-image',
|
||||
// name: 'fast-image',
|
||||
// component: () => import('@/views/FastImage.vue'),
|
||||
// meta: {
|
||||
// title: 'fastImage',
|
||||
// menuItem: true,
|
||||
// permission: "pass",
|
||||
// icon: 'btn_kjst'
|
||||
// }
|
||||
// },
|
||||
{
|
||||
path: 'fast-video',
|
||||
name: 'fast-video',
|
||||
component: () => import('@/views/FastVideo.vue'),
|
||||
|
|
@ -119,16 +121,6 @@ export const constantRoutes = [{
|
|||
permission: "pass",
|
||||
icon: 'btn_kjsp'
|
||||
}
|
||||
}, {
|
||||
path: 'video-gen',
|
||||
name: 'video-gen',
|
||||
component: () => import('@/views/VideoGen.vue'),
|
||||
meta: {
|
||||
title: 'videoGen',
|
||||
menuItem: true,
|
||||
permission: "pass",
|
||||
icon: 'btn_video'
|
||||
}
|
||||
}, {
|
||||
path: 'recharge',
|
||||
name: 'recharge',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ const messages = i18n.global.messages[lang];
|
|||
* @desc 创建axios实例
|
||||
*/
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API,
|
||||
// baseURL: process.env.VUE_APP_BASE_API,
|
||||
withCredentials: import.meta.env.MODE === 'development',
|
||||
timeout: 600 * 1000
|
||||
})
|
||||
|
|
|
|||
|
|
@ -68,28 +68,11 @@
|
|||
</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<!-- 模型选择 -->
|
||||
<div class="model-select">
|
||||
<div class="model-title">{{ $t('common.selectModel') || '选择模型' }}</div>
|
||||
<a-select v-model="selectedModel" style="width: 100%;">
|
||||
<a-option
|
||||
v-for="option in modelOptions"
|
||||
:key="option.value"
|
||||
:value="option.value">
|
||||
{{ option.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
<!-- 富文本编辑器 -->
|
||||
<RichTextEditor
|
||||
v-model="editorContent"
|
||||
:placeholder="$t('common.textVideoPlaceholder') || '请输入文本生成视频...'"
|
||||
:uploaded-images="uploadedImages"
|
||||
@text-change="handleTextChange"
|
||||
@image-upload="handleImageUpload"
|
||||
/>
|
||||
|
||||
<!-- <div class="text">
|
||||
<a-textarea
|
||||
v-model="text"
|
||||
:placeholder="$t('common.textVideoPlaceholder')" />
|
||||
</div> -->
|
||||
<mf-button
|
||||
class="submit"
|
||||
type="primary"
|
||||
|
|
@ -192,8 +175,6 @@
|
|||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -201,7 +182,6 @@ export default {
|
|||
firstUrl: '',
|
||||
lastUrl: '',
|
||||
text: '',
|
||||
editorContent: '',
|
||||
interval: null,
|
||||
videoUrl: null,
|
||||
videoLoading: false,
|
||||
|
|
@ -222,20 +202,9 @@ export default {
|
|||
templateLoading: false,
|
||||
selectedTemplate: null,
|
||||
selectedTemplatePreview: '', // 选中的模版预览图URL
|
||||
maxPollAttempts: 40, // 最大轮询次数(3秒 * 40 = 120秒超时)
|
||||
// 模型选择
|
||||
modelOptions: [
|
||||
{ label: 'Seedance 2.0', value: 'ep-20260326165811-dlkth' },
|
||||
{ label: 'Seedance 2.0 Fast', value: 'ep-20260326170056-dkj9m' }
|
||||
],
|
||||
selectedModel: 'ep-20260326165811-dlkth',
|
||||
// 已上传的图片列表(用于@功能)
|
||||
uploadedImages: []
|
||||
maxPollAttempts: 40 // 最大轮询次数(3秒 * 40 = 120秒超时)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
RichTextEditor
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.destroyInterval()
|
||||
},
|
||||
|
|
@ -344,28 +313,16 @@ export default {
|
|||
// 获取模板名称(根据当前语言)
|
||||
getTemplateName(template) {
|
||||
if (!template) return ''
|
||||
// 繁体中文显示 chineseContent,其他语言显示 englishContent
|
||||
// 如果是中文繁体,显示 chineseContent
|
||||
if (this.lang === 'zh_HK') {
|
||||
return template.chineseContent || template.name || ''
|
||||
}else{
|
||||
return template.englishContent || template.name || ''
|
||||
}
|
||||
},
|
||||
// 处理富文本内容变化
|
||||
handleTextChange(content) {
|
||||
this.editorContent = content
|
||||
// 同步到旧的 text 字段以保持兼容性
|
||||
this.text = content
|
||||
},
|
||||
// 处理上传的图片(用于@功能)
|
||||
handleImageUpload(imageInfo) {
|
||||
if (imageInfo && imageInfo.url) {
|
||||
this.uploadedImages.push({
|
||||
url: imageInfo.url,
|
||||
name: imageInfo.name || 'image'
|
||||
})
|
||||
}
|
||||
|
||||
// 如果是英文,显示 englishContent
|
||||
else if (this.lang === 'en_US') {
|
||||
return template.englishContent || template.name || ''
|
||||
}
|
||||
// 默认返回 name
|
||||
return template.name || ''
|
||||
},
|
||||
// 确认选择模板
|
||||
handleConfirmTemplate() {
|
||||
|
|
@ -525,10 +482,9 @@ export default {
|
|||
|
||||
this.generateLoading = true
|
||||
let params = {
|
||||
text: this.editorContent || this.text,
|
||||
text: this.text,
|
||||
firstUrl: firstImageUrl,
|
||||
functionType: '21',
|
||||
model: this.selectedModel // 新增模型参数
|
||||
functionType: '21'
|
||||
}
|
||||
if (this.lastUrl && this.lastUrl.url) {
|
||||
params.lastUrl = this.lastUrl.url
|
||||
|
|
@ -650,76 +606,8 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.upload {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.model-select {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.model-title {
|
||||
color: #fff;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.arco-select) {
|
||||
background-color: #1a1b20;
|
||||
border-color: rgba(255,255,255,0.1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 富文本编辑器样式 */
|
||||
.rich-editor-root {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding: 8px;
|
||||
background-color: #1a1b20;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
|
||||
.tool-btn {
|
||||
padding: 6px 12px;
|
||||
background-color: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
border-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rich-editor {
|
||||
min-height: 160px;
|
||||
padding: 16px;
|
||||
background-color: #1a1b20;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
outline: none;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
border-color: rgb(var(--primary-6));
|
||||
}
|
||||
|
||||
&[data-placeholder]:empty::before {
|
||||
content: attr(data-placeholder);
|
||||
color: #5c5d68;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.upload {
|
||||
margin-bottom: 20px;
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -61,28 +61,13 @@
|
|||
</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<!-- 模型选择 -->
|
||||
<div class="model-select">
|
||||
<div class="model-title">{{ $t('common.selectModel') || '选择模型' }}</div>
|
||||
<a-select v-model="selectedModel" style="width: 100%;">
|
||||
<a-option
|
||||
v-for="option in modelOptions"
|
||||
:key="option.value"
|
||||
:value="option.value">
|
||||
{{ option.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
<!-- 富文本编辑器 -->
|
||||
<RichTextEditor
|
||||
v-model="editorContent"
|
||||
:placeholder="$t('common.textPlaceholder') || '请输入文本生成图片...'"
|
||||
:uploaded-images="uploadedImages"
|
||||
@text-change="handleTextChange"
|
||||
@image-upload="handleImageUpload"
|
||||
/>
|
||||
|
||||
<!-- <div
|
||||
class="text"
|
||||
v-if="current == 2">
|
||||
<a-textarea
|
||||
v-model="text"
|
||||
:placeholder="$t('common.textPlaceholder')" />
|
||||
</div> -->
|
||||
<mf-button
|
||||
class="submit"
|
||||
type="primary"
|
||||
|
|
@ -172,7 +157,6 @@
|
|||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
|
|
@ -195,20 +179,9 @@ export default {
|
|||
templateList: [],
|
||||
templateLoading: false,
|
||||
selectedTemplate: null,
|
||||
selectedTemplatePreview: '', // 选中的模版预览图URL
|
||||
// 模型选择 - 支持 Seedance 2.0
|
||||
modelOptions: [
|
||||
{ label: 'Seedance 2.0', value: 'ep-20260326165811-dlkth' },
|
||||
{ label: 'Seedance 2.0 Fast', value: 'ep-20260326170056-dkj9m' }
|
||||
],
|
||||
selectedModel: 'ep-20260326165811-dlkth',
|
||||
// 已上传的图片列表(用于@功能)
|
||||
uploadedImages: []
|
||||
selectedTemplatePreview: '' // 选中的模版预览图URL
|
||||
}
|
||||
},
|
||||
components: {
|
||||
RichTextEditor
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['lang']),
|
||||
},
|
||||
|
|
@ -338,11 +311,16 @@ export default {
|
|||
// 获取模板名称(根据当前语言)
|
||||
getTemplateName(template) {
|
||||
if (!template) return ''
|
||||
// 繁体中文显示 chineseContent,其他语言显示 englishContent
|
||||
// 如果是中文繁体,显示 chineseContent
|
||||
if (this.lang === 'zh_HK') {
|
||||
return template.chineseContent || template.name || ''
|
||||
}
|
||||
return template.englishContent || template.name || ''
|
||||
// 如果是英文,显示 englishContent
|
||||
else if (this.lang === 'en_US') {
|
||||
return template.englishContent || template.name || ''
|
||||
}
|
||||
// 默认返回 name
|
||||
return template.name || ''
|
||||
},
|
||||
// 确认选择模板
|
||||
handleConfirmTemplate() {
|
||||
|
|
@ -360,21 +338,6 @@ export default {
|
|||
this.templateDialogVisible = false
|
||||
// 不重置selectedTemplate,保持用户的选择状态,方便二次选择
|
||||
},
|
||||
// 处理富文本内容变化
|
||||
handleTextChange(content) {
|
||||
this.editorContent = content
|
||||
// 同步到旧的 text 字段以保持兼容性
|
||||
this.text = content
|
||||
},
|
||||
// 处理上传的图片(用于@功能)
|
||||
handleImageUpload(imageInfo) {
|
||||
if (imageInfo && imageInfo.url) {
|
||||
this.uploadedImages.push({
|
||||
url: imageInfo.url,
|
||||
name: imageInfo.name || 'image'
|
||||
})
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.showResult = false
|
||||
},
|
||||
|
|
@ -438,11 +401,10 @@ export default {
|
|||
url: 'api/ai/imgToImg',
|
||||
method: 'POST',
|
||||
data: {
|
||||
text: this.editorContent || this.text,
|
||||
text: this.text,
|
||||
firstUrl: this.firstUrl.url,
|
||||
functionType: this.current == 1 ? '11' : '12',
|
||||
tags: tags.join(','),
|
||||
model: this.selectedModel // 新增模型参数
|
||||
tags: tags.join(',')
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
|
|
@ -536,77 +498,9 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.upload {
|
||||
.upload {
|
||||
// margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.model-select {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.model-title {
|
||||
color: #fff;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:deep(.arco-select) {
|
||||
background-color: #1a1b20;
|
||||
border-color: rgba(255,255,255,0.1);
|
||||
}
|
||||
}
|
||||
|
||||
/* 富文本编辑器样式 */
|
||||
.rich-editor-root {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding: 8px;
|
||||
background-color: #1a1b20;
|
||||
border-radius: 6px;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
|
||||
.tool-btn {
|
||||
padding: 6px 12px;
|
||||
background-color: rgba(255,255,255,0.05);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
border-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rich-editor {
|
||||
min-height: 160px;
|
||||
padding: 16px;
|
||||
background-color: #1a1b20;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
outline: none;
|
||||
resize: none;
|
||||
|
||||
&:focus {
|
||||
border-color: rgb(var(--primary-6));
|
||||
}
|
||||
|
||||
&[data-placeholder]:empty::before {
|
||||
content: attr(data-placeholder);
|
||||
color: #5c5d68;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -1,436 +0,0 @@
|
|||
<template>
|
||||
<div :class="prefixCls">
|
||||
<div class="left">
|
||||
<!-- 模式切换 -->
|
||||
<div class="mode-tabs">
|
||||
<button
|
||||
:class="['mode-tab', { active: mode === 'text-to-video' }]"
|
||||
@click="switchMode('text-to-video')">
|
||||
文生视频
|
||||
</button>
|
||||
<button
|
||||
:class="['mode-tab', { active: mode === 'image-to-video' }]"
|
||||
@click="switchMode('image-to-video')">
|
||||
图生视频
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 上传区域 - 根据模式显示 -->
|
||||
<div class="upload" v-if="mode === 'image-to-video'">
|
||||
<div class="upload-title">
|
||||
<div class="upload-title-left">
|
||||
{{ $t('common.uploadFirstImage') || '上传参考图' }}
|
||||
</div>
|
||||
<div class="upload-title-tip">
|
||||
{{ $t('common.uploadImageTip') || '支持PNG/JPG,最大10MB' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mf-image-upload
|
||||
listType="picture-card"
|
||||
uploadHeight="180px"
|
||||
:show-file-list="false"
|
||||
:content="$t('common.uploadFirstPlaceholder') || '点击上传参考图片'"
|
||||
v-model="firstUrl" />
|
||||
|
||||
<!-- 可选:上传尾帧 -->
|
||||
<div class="last-frame" v-if="showLastFrame">
|
||||
<div class="upload-title-left">
|
||||
{{ $t('common.uploadLastPlaceholder') || '上传尾帧(可选)' }}
|
||||
</div>
|
||||
<mf-image-upload
|
||||
listType="picture-card"
|
||||
uploadHeight="120px"
|
||||
:show-file-list="false"
|
||||
:content="$t('common.uploadLastPlaceholder') || '点击上传尾帧'"
|
||||
v-model="lastUrl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 模型选择 -->
|
||||
<div class="model-select">
|
||||
<div class="model-title">{{ $t('common.selectModel') || '选择模型' }}</div>
|
||||
<a-select v-model="selectedModel" style="width: 100%;">
|
||||
<a-option
|
||||
v-for="option in modelOptions"
|
||||
:key="option.value"
|
||||
:value="option.value">
|
||||
{{ option.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
<!-- 富文本编辑器 - 加大输入框 -->
|
||||
<div class="rich-editor-container">
|
||||
<RichTextEditor
|
||||
v-model="editorContent"
|
||||
:placeholder="$t('common.textVideoPlaceholder') || '描述视频内容,例如:一个女孩在海边跳舞...'"
|
||||
:uploaded-images="uploadedImages"
|
||||
@text-change="handleTextChange"
|
||||
@image-upload="handleImageUpload"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<mf-button
|
||||
class="submit"
|
||||
type="primary"
|
||||
size="large"
|
||||
:loading="generateLoading"
|
||||
@click="generateVideo">
|
||||
{{
|
||||
price
|
||||
? `${$t('common.createVideo', { price: price })}`
|
||||
: $t('common.generateVideo')
|
||||
}}
|
||||
</mf-button>
|
||||
<div class="submit-tip">
|
||||
{{ $t('common.generateTip') || '生成视频需要消耗余额' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧结果区 -->
|
||||
<div class="right" :class="{ 'has-result': showResult }">
|
||||
<div v-if="!showResult" class="empty-state">
|
||||
<img src="/images/empty-video.png" alt="视频生成" />
|
||||
<p>生成的视频将在这里显示</p>
|
||||
</div>
|
||||
|
||||
<div v-else class="result-container">
|
||||
<div class="result-video-wrapper">
|
||||
<video
|
||||
v-if="videoUrl"
|
||||
:src="videoUrl"
|
||||
controls
|
||||
autoplay
|
||||
class="result-video"
|
||||
:poster="firstUrl?.url || ''">
|
||||
您的浏览器不支持视频播放。
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<div class="result-actions">
|
||||
<mf-button v-if="canCancel" @click="cancelTask" type="danger">
|
||||
取消任务
|
||||
</mf-button>
|
||||
<mf-button @click="saveVideo" :disabled="!videoUrl">
|
||||
<a-image src="/images/btn_save.png" /> 保存视频
|
||||
</mf-button>
|
||||
<mf-button @click="closeResult">
|
||||
<a-image src="/images/btn_close.png" /> 关闭
|
||||
</mf-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import RichTextEditor from '@/components/RichTextEditor.vue'
|
||||
|
||||
export default {
|
||||
name: 'VideoGen',
|
||||
data() {
|
||||
return {
|
||||
prefixCls: 'video-gen',
|
||||
mode: 'text-to-video', // 'text-to-video' 或 'image-to-video'
|
||||
firstUrl: '',
|
||||
lastUrl: '',
|
||||
editorContent: '',
|
||||
interval: null,
|
||||
videoUrl: null,
|
||||
videoLoading: false,
|
||||
generateLoading: false,
|
||||
videoId: null,
|
||||
showResult: false,
|
||||
price: null,
|
||||
id: null,
|
||||
modelOptions: [
|
||||
{ label: 'Seedance 2.0', value: 'ep-20260326165811-dlkth' },
|
||||
{ label: 'Seedance 2.0 Fast', value: 'ep-20260326170056-dkj9m' }
|
||||
],
|
||||
selectedModel: 'ep-20260326165811-dlkth',
|
||||
uploadedImages: [],
|
||||
showLastFrame: false,
|
||||
maxPollAttempts: 40
|
||||
}
|
||||
},
|
||||
components: {
|
||||
RichTextEditor
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['lang'])
|
||||
},
|
||||
mounted() {
|
||||
this.loadPriceInfo()
|
||||
},
|
||||
methods: {
|
||||
async loadPriceInfo() {
|
||||
this.$axios({
|
||||
url: 'api/manager/selectInfo',
|
||||
method: 'GET',
|
||||
data: { aiType: '21' }
|
||||
}).then((res) => {
|
||||
this.price = res.data?.price
|
||||
this.id = res.data?.id
|
||||
})
|
||||
},
|
||||
|
||||
handleTextChange(content) {
|
||||
this.editorContent = content
|
||||
},
|
||||
|
||||
handleImageUpload(imageInfo) {
|
||||
if (imageInfo && imageInfo.url) {
|
||||
this.uploadedImages.push({
|
||||
url: imageInfo.url,
|
||||
name: imageInfo.name || 'image'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
generateVideo() {
|
||||
if (this.mode === 'image-to-video') {
|
||||
const firstImageUrl = typeof this.firstUrl === 'object' ? this.firstUrl.url : this.firstUrl
|
||||
if (!firstImageUrl) {
|
||||
this.$message.error(this.$t('common.uploadFirstImageError') || '请上传参考图')
|
||||
return
|
||||
}
|
||||
} else if (!this.editorContent.trim()) {
|
||||
this.$message.error('请输入视频描述文本')
|
||||
return
|
||||
}
|
||||
|
||||
this.generateLoading = true
|
||||
|
||||
const params = {
|
||||
text: this.editorContent || '一个优雅的女孩在阳光下跳舞',
|
||||
functionType: '21',
|
||||
model: this.selectedModel
|
||||
}
|
||||
|
||||
// 图生视频模式需要上传图片
|
||||
if (this.mode === 'image-to-video') {
|
||||
const firstImageUrl = typeof this.firstUrl === 'object' ? this.firstUrl.url : this.firstUrl
|
||||
params.firstUrl = firstImageUrl
|
||||
|
||||
if (this.lastUrl) {
|
||||
params.lastUrl = typeof this.lastUrl === 'object' ? this.lastUrl.url : this.lastUrl
|
||||
}
|
||||
}
|
||||
|
||||
this.$axios({
|
||||
url: 'api/ai/imgToVideo',
|
||||
method: 'POST',
|
||||
data: params
|
||||
}).then((res) => {
|
||||
this.generateLoading = false
|
||||
if (res.code == 200) {
|
||||
this.videoId = res.data.id
|
||||
this.showResult = true
|
||||
this.getVideo(res.data.id)
|
||||
} else if (res.code == -1) {
|
||||
this.$confirm({
|
||||
title: this.$t('common.notice'),
|
||||
content: this.$t('common.balenceLow'),
|
||||
onOk: () => this.$router.push('/recharge')
|
||||
})
|
||||
}
|
||||
}).catch(() => {
|
||||
this.generateLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
getVideo(videoId) {
|
||||
let attempts = 0
|
||||
this.interval = setInterval(() => {
|
||||
attempts++
|
||||
if (attempts > this.maxPollAttempts) {
|
||||
this.$message.warning('视频生成超时')
|
||||
this.destroyInterval()
|
||||
return
|
||||
}
|
||||
|
||||
this.$axios({
|
||||
url: `api/ai/${videoId}`,
|
||||
method: 'GET'
|
||||
}).then((res) => {
|
||||
if (res.code == 200 && res.data.status === 'succeeded') {
|
||||
this.videoUrl = res.data.content?.video_url || res.data.video_url
|
||||
this.destroyInterval()
|
||||
}
|
||||
})
|
||||
}, 3000)
|
||||
},
|
||||
|
||||
destroyInterval() {
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval)
|
||||
this.interval = null
|
||||
}
|
||||
},
|
||||
|
||||
saveVideo() {
|
||||
if (!this.videoUrl) return
|
||||
const link = document.createElement('a')
|
||||
link.href = this.videoUrl
|
||||
link.download = `video_${Date.now()}.mp4`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
},
|
||||
|
||||
closeResult() {
|
||||
this.showResult = false
|
||||
this.videoUrl = null
|
||||
this.videoId = null
|
||||
this.taskStatus = null
|
||||
},
|
||||
|
||||
// 取消任务
|
||||
async cancelTask() {
|
||||
if (!this.videoId) return
|
||||
|
||||
this.$confirm({
|
||||
title: '取消任务',
|
||||
content: '确定要取消当前视频生成任务吗?取消后余额将退回。',
|
||||
okText: '确定取消',
|
||||
cancelText: '关闭',
|
||||
onOk: async () => {
|
||||
try {
|
||||
const res = await this.$axios({
|
||||
url: `api/ai/${this.videoId}/cancel`,
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
if (res.code === 200) {
|
||||
this.$message.success('任务已取消,余额已退回')
|
||||
this.destroyInterval()
|
||||
this.showResult = false
|
||||
this.videoUrl = null
|
||||
this.videoId = null
|
||||
} else {
|
||||
this.$message.error(res.msg || '取消失败')
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('取消请求失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 计算属性:是否可以取消
|
||||
canCancel() {
|
||||
return this.videoId && !this.videoUrl
|
||||
}
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.destroyInterval()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.video-gen {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
background: #0f1014;
|
||||
|
||||
.left {
|
||||
width: 480px;
|
||||
background: #1a1b20;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
font-size: 22px;
|
||||
color: #fff;
|
||||
margin-bottom: 24px;
|
||||
font-weight: 600;
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-left: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.model-select {
|
||||
margin: 16px 0;
|
||||
|
||||
.model-title {
|
||||
color: #ddd;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.rich-editor-container {
|
||||
flex: 1;
|
||||
min-height: 320px;
|
||||
margin: 16px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:deep(.rich-editor-root) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:deep(.rich-editor) {
|
||||
flex: 1;
|
||||
min-height: 280px !important;
|
||||
font-size: 16px;
|
||||
line-height: 1.75;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.submit {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 1;
|
||||
background: #000;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&.has-result {
|
||||
align-items: flex-start;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
|
||||
img {
|
||||
width: 120px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.result-video-wrapper {
|
||||
width: 100%;
|
||||
max-width: 720px;
|
||||
}
|
||||
|
||||
.result-video {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue