|
@@ -0,0 +1,970 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="chat-interface">
|
|
|
|
|
+ <!-- 生成类型选项卡 -->
|
|
|
|
|
+ <div class="generation-tabs">
|
|
|
|
|
+ <el-tabs v-model="activeTab" type="card">
|
|
|
|
|
+ <el-tab-pane label="视频生成" name="video">
|
|
|
|
|
+ <template #label>
|
|
|
|
|
+ <div class="tab-label">
|
|
|
|
|
+ <el-icon class="tab-icon"><VideoPlay /></el-icon>
|
|
|
|
|
+ <span>视频生成</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-tab-pane>
|
|
|
|
|
+ <el-tab-pane label="图片生成" name="image">
|
|
|
|
|
+ <template #label>
|
|
|
|
|
+ <div class="tab-label">
|
|
|
|
|
+ <el-icon class="tab-icon"><Picture /></el-icon>
|
|
|
|
|
+ <span>图片生成</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-tab-pane>
|
|
|
|
|
+ </el-tabs>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 输入区域容器 -->
|
|
|
|
|
+ <div class="input-container">
|
|
|
|
|
+ <!-- 上传区域:上传按钮和已上传图片水平排列 -->
|
|
|
|
|
+ <div class="upload-area">
|
|
|
|
|
+ <!-- 上传按钮 -->
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="default"
|
|
|
|
|
+ class="add-btn"
|
|
|
|
|
+ @click="triggerUpload"
|
|
|
|
|
+ title="上传"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-icon><Plus /></el-icon>
|
|
|
|
|
+ <span>上传</span>
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 已上传图片预览 -->
|
|
|
|
|
+ <div class="uploaded-images-container">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="(img, index) in uploadedImages"
|
|
|
|
|
+ :key="index"
|
|
|
|
|
+ class="message-image"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- 使用自定义图片预览功能 -->
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ :src="img.url"
|
|
|
|
|
+ fit="cover"
|
|
|
|
|
+ @click="handleImageClick(img)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="text"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ class="delete-img-btn"
|
|
|
|
|
+ @click.stop="removeImage(index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-icon><Delete /></el-icon>
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 隐藏的文件输入框 -->
|
|
|
|
|
+ <input
|
|
|
|
|
+ ref="fileInput"
|
|
|
|
|
+ type="file"
|
|
|
|
|
+ accept="image/*"
|
|
|
|
|
+ style="display: none"
|
|
|
|
|
+ @change="handleFileChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 输入区域:输入框和发送按钮 -->
|
|
|
|
|
+ <div class="input-wrapper">
|
|
|
|
|
+ <!-- 文本输入框 -->
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="prompt"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ :placeholder="getPlaceholder"
|
|
|
|
|
+ @paste="handlePaste"
|
|
|
|
|
+ class="chat-input"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 右侧提交按钮 -->
|
|
|
|
|
+ <el-button type="primary" class="send-btn" @click="handleSubmit" :loading="uploading">
|
|
|
|
|
+ 提交
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-form inline>
|
|
|
|
|
+ <el-form-item>
|
|
|
|
|
+ <el-input v-model="searchInfo" placeholder="搜索关键字" clearable style="width: 300px;" />
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 文件夹筛选下拉菜单 -->
|
|
|
|
|
+ <el-dropdown @command="handleFolderCommand" style="margin-right: 10px;">
|
|
|
|
|
+ <el-button icon="search" title="文件夹筛选">
|
|
|
|
|
+ {{ selectedFolder || '文件夹筛选' }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <template #dropdown>
|
|
|
|
|
+ <el-dropdown-menu>
|
|
|
|
|
+ <el-dropdown-item command="">全部文件夹</el-dropdown-item>
|
|
|
|
|
+ <el-dropdown-item v-for="(folder, index) in folderList" :key="index" :command="folder">
|
|
|
|
|
+ {{ folder }}
|
|
|
|
|
+ </el-dropdown-item>
|
|
|
|
|
+ </el-dropdown-menu>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-dropdown>
|
|
|
|
|
+
|
|
|
|
|
+ <el-button type="primary" icon="search" @click="onSubmit" title="搜索">查询</el-button>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </el-form>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 表格展示 -->
|
|
|
|
|
+ <el-table
|
|
|
|
|
+ ref="multipleTable"
|
|
|
|
|
+ style="width: 100%; height: 62vh;"
|
|
|
|
|
+ :row-style="{ height: '20px' }"
|
|
|
|
|
+ :header-cell-style="{ padding: '0px' }"
|
|
|
|
|
+ :cell-style="{ padding: '0px' }"
|
|
|
|
|
+ :header-row-style="{ height: '20px' }"
|
|
|
|
|
+ border tooltip-effect="dark"
|
|
|
|
|
+ :data="tableData1"
|
|
|
|
|
+ row-key="ID"
|
|
|
|
|
+ highlight-current-row
|
|
|
|
|
+ :cell-class-name="tableDataCellClass"
|
|
|
|
|
+ @selection-change="SelectionChange"
|
|
|
|
|
+ @row-dblclick="onRowDblClick"
|
|
|
|
|
+ :show-overflow-tooltip="true"
|
|
|
|
|
+ >
|
|
|
|
|
+ <el-table-column type="selection" width="55" />
|
|
|
|
|
+ <el-table-column label="ID" prop="id" width="70" />
|
|
|
|
|
+ <el-table-column label="第一段" prop="chinese_description" width="300" />
|
|
|
|
|
+ <el-table-column label="第二段" prop="english_description" width="300" />
|
|
|
|
|
+ <el-table-column label="图片名称" prop="img_name" width="300" />
|
|
|
|
|
+ <el-table-column label="原图" width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ :src="formatImageUrl(row.old_image_url)"
|
|
|
|
|
+ :preview-src-list="[formatImageUrl(row.old_image_url)]"
|
|
|
|
|
+ style="width: 90px; height: 70px;"
|
|
|
|
|
+ fit="contain"
|
|
|
|
|
+ preview-teleported
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ v-if="tableData1.some(row => row.model === 'black-forest-labs/FLUX.1-kontext-pro')"
|
|
|
|
|
+ label="FLUX.1"
|
|
|
|
|
+ width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ v-if="row.model === 'black-forest-labs/FLUX.1-kontext-pro'"
|
|
|
|
|
+ :src="formatImageUrl(row.new_image_url)"
|
|
|
|
|
+ :preview-src-list="[formatImageUrl(row.new_image_url)]"
|
|
|
|
|
+ style="width: 90px; height: 70px;"
|
|
|
|
|
+ fit="contain"
|
|
|
|
|
+ preview-teleported
|
|
|
|
|
+ />
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ v-if="tableData1.some(row => row.model === 'dall-e-3')"
|
|
|
|
|
+ label="dall-e-3"
|
|
|
|
|
+ width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ v-if="row.model === 'dall-e-3'"
|
|
|
|
|
+ :src="formatImageUrl(row.new_image_url)"
|
|
|
|
|
+ :preview-src-list="[formatImageUrl(row.new_image_url)]"
|
|
|
|
|
+ style="width: 90px; height: 70px;"
|
|
|
|
|
+ fit="contain"
|
|
|
|
|
+ preview-teleported
|
|
|
|
|
+ />
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ v-if="tableData1.some(row => row.model === 'gpt-image-1')"
|
|
|
|
|
+ label="gpt-image-1"
|
|
|
|
|
+ width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ v-if="row.model === 'gpt-image-1'"
|
|
|
|
|
+ :src="formatImageUrl(row.new_image_url)"
|
|
|
|
|
+ :preview-src-list="[formatImageUrl(row.new_image_url)]"
|
|
|
|
|
+ style="width: 90px; height: 70px;"
|
|
|
|
|
+ fit="contain"
|
|
|
|
|
+ preview-teleported
|
|
|
|
|
+ />
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ <el-table-column
|
|
|
|
|
+ v-if="tableData1.some(row => row.model === 'MID_JOURNEY')"
|
|
|
|
|
+ label="MID_JOURNEY"
|
|
|
|
|
+ width="130">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ v-if="row.model === 'MID_JOURNEY'"
|
|
|
|
|
+ :src="`https://chatapi.onechats.ai/mj/image/${row.taskId}`"
|
|
|
|
|
+ :preview-src-list="[`https://chatapi.onechats.ai/mj/image/${row.taskId}`]"
|
|
|
|
|
+ style="width: 90px; height: 70px;"
|
|
|
|
|
+ fit="contain"
|
|
|
|
|
+ preview-teleported
|
|
|
|
|
+ />
|
|
|
|
|
+ <span v-else>-</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+
|
|
|
|
|
+ <el-table-column label="图生图预览" width="120">
|
|
|
|
|
+ <template #default="{ row }">
|
|
|
|
|
+ <el-image
|
|
|
|
|
+ :src="formatImageUrl(row.imgtoimg_url)"
|
|
|
|
|
+ :preview-src-list="[formatImageUrl(row.imgtoimg_url)]"
|
|
|
|
|
+ style="width: 90px; height: 70px;"
|
|
|
|
|
+ fit="contain"
|
|
|
|
|
+ preview-teleported
|
|
|
|
|
+ />
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-table-column>
|
|
|
|
|
+ </el-table>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 分页 -->
|
|
|
|
|
+ <div class="gva-pagination">
|
|
|
|
|
+ <el-pagination
|
|
|
|
|
+ @size-change="handleSizeChange"
|
|
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
|
|
+ :current-page="page"
|
|
|
|
|
+ :page-sizes="[10, 30, 50, 100]"
|
|
|
|
|
+ :page-size="pageSize"
|
|
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
|
+ :total="total"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, computed, onMounted } from 'vue'
|
|
|
|
|
+import { Delete, ZoomIn, CirclePlus, VideoPlay, Picture } from '@element-plus/icons-vue'
|
|
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
|
|
+import { useUserStore } from '@/pinia/modules/user'
|
|
|
|
|
+import { isImageMime } from '@/utils/image'
|
|
|
|
|
+import service from '@/utils/request'
|
|
|
|
|
+import {imageToText,getTable, Template_ids,txttoimg_moxing,GetHttpUrl,txttoimg_update, getSide} from '@/api/mes/job'
|
|
|
|
|
+
|
|
|
|
|
+//获取登录用户信息
|
|
|
|
|
+const userStore = useUserStore()
|
|
|
|
|
+const _username = ref('')
|
|
|
|
|
+_username.value = userStore.userInfo.userName + '/' + userStore.userInfo.nickName
|
|
|
|
|
+console.log('获取用户信息',_username.value)
|
|
|
|
|
+console.log('获取用户名称',userStore.userInfo.nickName)
|
|
|
|
|
+
|
|
|
|
|
+//获取服务器地址
|
|
|
|
|
+const baseUrl = ref('')
|
|
|
|
|
+const port = ref('')
|
|
|
|
|
+const full_url = ref('')
|
|
|
|
|
+// 从接口获取服务器地址
|
|
|
|
|
+const fetchServerUrl = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await GetHttpUrl()
|
|
|
|
|
+ if (res.code === 0 && res.data && res.data.full_url) {
|
|
|
|
|
+ full_url.value = res.data.full_url
|
|
|
|
|
+ baseUrl.value = res.data.baseUrl
|
|
|
|
|
+ port.value = res.data.port
|
|
|
|
|
+ console.log('获取服务器地址',full_url.value)
|
|
|
|
|
+ console.log('IP地址',baseUrl.value)
|
|
|
|
|
+ console.log('端口',port.value)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取服务器地址失败:', error)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+fetchServerUrl();
|
|
|
|
|
+
|
|
|
|
|
+const tableData1 = ref([])
|
|
|
|
|
+const selectedFolder = ref('')
|
|
|
|
|
+const folderList = ref([])
|
|
|
|
|
+
|
|
|
|
|
+const getTableData = async () => {
|
|
|
|
|
+ const res = await getTable({
|
|
|
|
|
+ search: searchInfo.value,
|
|
|
|
|
+ limit: pageSize.value,
|
|
|
|
|
+ page: page.value,
|
|
|
|
|
+ folder: selectedFolder.value
|
|
|
|
|
+ })
|
|
|
|
|
+ tableData1.value = res.data.list
|
|
|
|
|
+ total.value = res.data.total
|
|
|
|
|
+
|
|
|
|
|
+ // 更新文件夹列表
|
|
|
|
|
+ if (res.data.folder) {
|
|
|
|
|
+ folderList.value = res.data.folder
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // const res_Template = await Template_ids({path:row['old_image_url']});
|
|
|
|
|
+ // height.value = res_Template.data.height
|
|
|
|
|
+ // width.value = res_Template.data.width
|
|
|
|
|
+}
|
|
|
|
|
+getTableData()
|
|
|
|
|
+
|
|
|
|
|
+// 处理文件夹选择
|
|
|
|
|
+const handleFolderCommand = (command) => {
|
|
|
|
|
+ selectedFolder.value = command
|
|
|
|
|
+ onSubmit()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 消息内容
|
|
|
|
|
+const prompt = ref('')
|
|
|
|
|
+// 已上传图片列表
|
|
|
|
|
+const uploadedImages = ref([])
|
|
|
|
|
+// 文件输入框引用
|
|
|
|
|
+const fileInput = ref(null)
|
|
|
|
|
+// 上传状态
|
|
|
|
|
+const uploading = ref(false)
|
|
|
|
|
+// 激活的标签页
|
|
|
|
|
+const activeTab = ref('image')
|
|
|
|
|
+// 生成类型
|
|
|
|
|
+const generationType = computed(() => activeTab.value === 'video' ? '视频生成' : '图片生成')
|
|
|
|
|
+// API路径
|
|
|
|
|
+const path = ref(import.meta.env.VITE_BASE_API)
|
|
|
|
|
+
|
|
|
|
|
+// 触发文件上传
|
|
|
|
|
+const triggerUpload = () => {
|
|
|
|
|
+ fileInput.value?.click()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理文件选择
|
|
|
|
|
+const handleFileChange = (e) => {
|
|
|
|
|
+ const file = e.target.files[0]
|
|
|
|
|
+ if (file) {
|
|
|
|
|
+ processImageFile(file)
|
|
|
|
|
+ }
|
|
|
|
|
+ // 清空文件输入
|
|
|
|
|
+ if (fileInput.value) {
|
|
|
|
|
+ fileInput.value.value = ''
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理粘贴事件
|
|
|
|
|
+const handlePaste = (e) => {
|
|
|
|
|
+ console.log('粘贴事件触发')
|
|
|
|
|
+ const items = e.clipboardData.items
|
|
|
|
|
+ console.log('剪贴板项目:', items)
|
|
|
|
|
+
|
|
|
|
|
+ for (let i = 0; i < items.length; i++) {
|
|
|
|
|
+ console.log('项目', i, '类型:', items[i].type)
|
|
|
|
|
+ if (items[i].type.indexOf('image') !== -1) {
|
|
|
|
|
+ const file = items[i].getAsFile()
|
|
|
|
|
+ console.log('获取到图片文件:', file)
|
|
|
|
|
+ processImageFile(file)
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理图片文件
|
|
|
|
|
+const processImageFile = (file) => {
|
|
|
|
|
+ // 验证文件类型
|
|
|
|
|
+ if (!isImageMime(file.type)) {
|
|
|
|
|
+ ElMessage.error('请选择JPG、PNG或WebP格式的图片')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 验证文件大小(限制5MB)
|
|
|
|
|
+ const maxSize = 5 * 1024 * 1024
|
|
|
|
|
+ if (file.size > maxSize) {
|
|
|
|
|
+ ElMessage.error('图片大小不能超过5MB')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 读取文件并添加到上传列表
|
|
|
|
|
+ const reader = new FileReader()
|
|
|
|
|
+ reader.onload = (e) => {
|
|
|
|
|
+ const imageUrl = e.target.result
|
|
|
|
|
+ // 检查图片是否已存在
|
|
|
|
|
+ const isDuplicate = uploadedImages.value.some(img => img.url === imageUrl)
|
|
|
|
|
+ if (!isDuplicate) {
|
|
|
|
|
+ uploadedImages.value.push({
|
|
|
|
|
+ url: imageUrl,
|
|
|
|
|
+ file: file
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ reader.readAsDataURL(file)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 删除图片(从已上传列表)
|
|
|
|
|
+const removeImage = (index) => {
|
|
|
|
|
+ uploadedImages.value.splice(index, 1)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 处理图片点击(放大查看)
|
|
|
|
|
+const handleImageClick = (img) => {
|
|
|
|
|
+ // 创建自定义图片预览
|
|
|
|
|
+ const previewContainer = document.createElement('div')
|
|
|
|
|
+ previewContainer.className = 'custom-image-preview'
|
|
|
|
|
+ previewContainer.style.cssText = `
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.9);
|
|
|
|
|
+ z-index: 9999;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ `
|
|
|
|
|
+
|
|
|
|
|
+ // 添加图片
|
|
|
|
|
+ const previewImage = document.createElement('img')
|
|
|
|
|
+ previewImage.src = img.url
|
|
|
|
|
+ previewImage.style.cssText = `
|
|
|
|
|
+ max-width: 90%;
|
|
|
|
|
+ max-height: 90%;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ `
|
|
|
|
|
+
|
|
|
|
|
+ // 添加关闭按钮
|
|
|
|
|
+ const closeButton = document.createElement('button')
|
|
|
|
|
+ closeButton.innerHTML = '×'
|
|
|
|
|
+ closeButton.style.cssText = `
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 20px;
|
|
|
|
|
+ right: 20px;
|
|
|
|
|
+ font-size: 30px;
|
|
|
|
|
+ color: white;
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ width: 30px;
|
|
|
|
|
+ height: 30px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ `
|
|
|
|
|
+
|
|
|
|
|
+ // 组装预览组件
|
|
|
|
|
+ previewContainer.appendChild(previewImage)
|
|
|
|
|
+ previewContainer.appendChild(closeButton)
|
|
|
|
|
+ document.body.appendChild(previewContainer)
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭预览的处理
|
|
|
|
|
+ const closePreview = () => {
|
|
|
|
|
+ document.body.removeChild(previewContainer)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ closeButton.addEventListener('click', closePreview)
|
|
|
|
|
+ previewContainer.addEventListener('click', (e) => {
|
|
|
|
|
+ if (e.target === previewContainer) {
|
|
|
|
|
+ closePreview()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // ESC键关闭
|
|
|
|
|
+ const handleEscKey = (e) => {
|
|
|
|
|
+ if (e.key === 'Escape') {
|
|
|
|
|
+ closePreview()
|
|
|
|
|
+ document.removeEventListener('keydown', handleEscKey)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ document.addEventListener('keydown', handleEscKey)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// 提交处理
|
|
|
|
|
+const handleSubmit = async () => {
|
|
|
|
|
+ if (!prompt.value.trim() && uploadedImages.value.length === 0) {
|
|
|
|
|
+ ElMessage.warning('请输入消息或上传图片')
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ uploading.value = true
|
|
|
|
|
+
|
|
|
|
|
+ // 准备提交数据
|
|
|
|
|
+ let status_val = ''
|
|
|
|
|
+
|
|
|
|
|
+ // 根据标签页和上传内容确定生成类型
|
|
|
|
|
+ if (activeTab.value === 'image') {
|
|
|
|
|
+ // 图片生成
|
|
|
|
|
+ status_val = uploadedImages.value.length > 0 ? '图生图' : '文生图'
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 视频生成
|
|
|
|
|
+ status_val = uploadedImages.value.length > 0 ? '图生视频' : '文生视频'
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const payload = {
|
|
|
|
|
+ status_val: status_val,
|
|
|
|
|
+ batch: uploadedImages.value.map(item => item.file), // 图片数组
|
|
|
|
|
+ prompt: prompt.value
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 打印调试区域
|
|
|
|
|
+ console.log(payload);
|
|
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
|
+ uploading.value = false;
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ const res = await imageToText(payload)
|
|
|
|
|
+
|
|
|
|
|
+ // 处理接口返回结果
|
|
|
|
|
+ if (res.code === 0) {
|
|
|
|
|
+ ElMessage.success('提交成功')
|
|
|
|
|
+ console.log('接口返回结果:', res)
|
|
|
|
|
+
|
|
|
|
|
+ // 清空输入和图片列表
|
|
|
|
|
+ prompt.value = ''
|
|
|
|
|
+ uploadedImages.value = []
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ElMessage.error(res.msg || '提交失败')
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('提交失败:', error)
|
|
|
|
|
+ ElMessage.error('提交失败,请稍后重试')
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ uploading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 计算预览列表
|
|
|
|
|
+const previewList = computed(() => {
|
|
|
|
|
+ return uploadedImages.value.map(item => item.url)
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 计算已选图片数量
|
|
|
|
|
+const selectedImagesCount = computed(() => {
|
|
|
|
|
+ return uploadedImages.value.length
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 根据生成类型获取占位符
|
|
|
|
|
+const getPlaceholder = computed(() => {
|
|
|
|
|
+ if (generationType.value === '视频生成') {
|
|
|
|
|
+ return '输入视频生成的提示词'
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '输入图片生成的提示词'
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 将DataURL转换为File对象
|
|
|
|
|
+const dataURLtoFile = (dataurl, filename) => {
|
|
|
|
|
+ const arr = dataurl.split(',')
|
|
|
|
|
+ const mime = arr[0].match(/:(.*?);/)[1]
|
|
|
|
|
+ const bstr = atob(arr[1])
|
|
|
|
|
+ let n = bstr.length
|
|
|
|
|
+ const u8arr = new Uint8Array(n)
|
|
|
|
|
+ while (n--) {
|
|
|
|
|
+ u8arr[n] = bstr.charCodeAt(n)
|
|
|
|
|
+ }
|
|
|
|
|
+ return new File([u8arr], filename, { type: mime })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style scoped>
|
|
|
|
|
+/* 生成类型选项卡 */
|
|
|
|
|
+.generation-tabs {
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.el-tabs__header) {
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.el-tabs__nav-wrap) {
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.el-tabs__nav) {
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.el-tabs__item) {
|
|
|
|
|
+ padding: 0 20px;
|
|
|
|
|
+ height: 40px;
|
|
|
|
|
+ line-height: 40px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: 0;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.el-tabs__item.is-active) {
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ background: transparent;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.el-tabs__active-bar) {
|
|
|
|
|
+ background-color: #409eff;
|
|
|
|
|
+ height: 2px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.tab-label) {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 6px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.generation-tabs :deep(.tab-icon) {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 聊天界面样式 */
|
|
|
|
|
+.chat-interface {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ width: 70%;
|
|
|
|
|
+ margin: 0 auto;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 输入区域容器 */
|
|
|
|
|
+.input-container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 上传图片列表容器 */
|
|
|
|
|
+.uploaded-images-container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ min-height: auto;
|
|
|
|
|
+ max-height: 150px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 单张图片样式 */
|
|
|
|
|
+.message-image {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 60px;
|
|
|
|
|
+ height: 60px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.message-image:hover {
|
|
|
|
|
+ transform: translateY(-1px);
|
|
|
|
|
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.message-image :deep(.el-image) {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ object-fit: cover;
|
|
|
|
|
+ cursor: zoom-in;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 删除按钮 */
|
|
|
|
|
+.delete-img-btn {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 2px;
|
|
|
|
|
+ right: 2px;
|
|
|
|
|
+ background-color: rgba(255, 255, 255, 0.8);
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ width: 20px;
|
|
|
|
|
+ height: 20px;
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ opacity: 0;
|
|
|
|
|
+ transition: opacity 0.3s ease;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 图片选择对话框样式 */
|
|
|
|
|
+.image-selector {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 15px;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ max-height: 600px;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.image-upload-area {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ height: 240px;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ border: 1px dashed #dcdfe6;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ background-color: #fafafa;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: all 0.3s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-box {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-icon {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-text {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: #606266;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-hint {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ margin-top: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.image-upload-area:hover {
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ background-color: #ecf5ff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+.image-upload-area:hover {
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ background-color: #ecf5ff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-box {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-icon {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ color: #c0c4cc;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.upload-box span {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 移除AI绘图文字相关样式 */
|
|
|
|
|
+.image-overlay {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.image-tags {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 图片预览容器 */
|
|
|
|
|
+.image-preview-container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 20px;
|
|
|
|
|
+ max-height: 70vh;
|
|
|
|
|
+ overflow: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.full-size-image {
|
|
|
|
|
+ max-width: 100%;
|
|
|
|
|
+ max-height: 100%;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.message-image:hover .delete-img-btn {
|
|
|
|
|
+ opacity: 1;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 上传区域:上传按钮和已上传图片水平排列 */
|
|
|
|
|
+.upload-area {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ background-color: #fafafa;
|
|
|
|
|
+ border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 上传按钮 */
|
|
|
|
|
+.add-btn {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ width: 60px;
|
|
|
|
|
+ height: 60px;
|
|
|
|
|
+ border: 2px dashed #dcdfe6;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.add-btn:hover {
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+ background-color: #ecf5ff;
|
|
|
|
|
+ box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.add-btn span {
|
|
|
|
|
+ display: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 已上传图片容器 */
|
|
|
|
|
+.uploaded-images-container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 消息图片 */
|
|
|
|
|
+.message-image {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ width: 60px;
|
|
|
|
|
+ height: 60px;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.message-image .el-image {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.input-wrapper {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ align-items: flex-end;
|
|
|
|
|
+ padding: 16px;
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.add-btn :deep(.el-icon) {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ margin-bottom: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 聊天输入框 */
|
|
|
|
|
+.chat-input {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ resize: none;
|
|
|
|
|
+ outline: none;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ line-height: 1.5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-textarea) {
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ margin: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-textarea__inner) {
|
|
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ resize: none;
|
|
|
|
|
+ padding: 12px 16px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ line-height: 1.5;
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
|
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
|
|
|
+ min-height: 80px;
|
|
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+:deep(.el-textarea__inner:focus) {
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
|
|
|
|
+ outline: none;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 发送按钮 */
|
|
|
|
|
+.send-btn {
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ padding: 8px 16px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ background-color: #409eff;
|
|
|
|
|
+ border-color: #409eff;
|
|
|
|
|
+ transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
|
|
|
+ align-self: flex-end;
|
|
|
|
|
+ box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.send-btn:hover {
|
|
|
|
|
+ background-color: #66b1ff;
|
|
|
|
|
+ border-color: #66b1ff;
|
|
|
|
|
+ transform: translateY(-1px);
|
|
|
|
|
+ box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 响应式设计 */
|
|
|
|
|
+@media (max-width: 768px) {
|
|
|
|
|
+ /* 输入容器响应式 */
|
|
|
|
|
+ .input-container {
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 上传区域响应式 */
|
|
|
|
|
+ .upload-area {
|
|
|
|
|
+ padding: 12px;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .add-btn {
|
|
|
|
|
+ width: 50px;
|
|
|
|
|
+ height: 50px;
|
|
|
|
|
+ font-size: 20px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .message-image {
|
|
|
|
|
+ width: 50px;
|
|
|
|
|
+ height: 50px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* 输入区域响应式 */
|
|
|
|
|
+ .input-wrapper {
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: stretch;
|
|
|
|
|
+ padding: 12px;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .chat-input {
|
|
|
|
|
+ min-height: 70px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .send-btn {
|
|
|
|
|
+ width: 44px;
|
|
|
|
|
+ height: 44px;
|
|
|
|
|
+ font-size: 18px;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|