Commit 5decc3ef authored by Administrator's avatar Administrator

wm_nano_banana

parent a98e92f0
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/home/index.vue'
import SampleHandleView from '../views/sample_handle/index.vue'
import WmNanoBananaView from '../views/wm_nano_banana/index.vue'
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
......@@ -19,6 +20,11 @@ const router = createRouter({
path: '/sample_handle',
name: 'sample_handle',
component: SampleHandleView
},
{
path: '/wm_nano_banana',
name: 'wm_nano_banana',
component: WmNanoBananaView
}
]
})
......
import aitoolsService from '@/api/service/aitoolsService'
// 检测设备类型
export const detectDeviceType = () => {
const userAgent = navigator.userAgent.toLowerCase()
let source = ''
if (userAgent.match(/mobile/i) || userAgent.match(/android/i) || userAgent.match(/iphone/i) || userAgent.match(/ipad/i)) {
source = 'mobile'
// if (userAgent.match(/iphone/i) || userAgent.match(/ipad/i)) {
// source = 'ios'
// } else if (userAgent.match(/android/i)) {
// source = 'android'
// }
if (userAgent.match(/micromessenger/i)) {
source = 'wechat'
}
} else {
source = 'pc'
}
console.log('设备类型:', source)
return source
}
// 记录用户操作
export const trackUserAction = async (source: string, user_id: string, content: string, action: string) => {
let param: any = {
source: source,
user_id: user_id,
content: content,
action: action,
}
aitoolsService.commonApi('提交用户轨迹数据', 'track', param)
.then((response) => {
if (response == 'ok') {
console.log(action, '上报成功')
} else {
console.log(action, '上报失败')
}
})
.catch((error) => {
console.log(action, '上报失败:', error)
})
}
import aitoolsService from '@/api/service/aitoolsService';
import { trackUserAction } from './common';
import { ElMessage, ElMessageBox } from 'element-plus';
import utils from '@/utils/utils';
import { reactive, ref } from 'vue';
// 客户留资
export const myCustomerInfo = (form: any, title: any) => {
const customer = reactive({
name: '',
mobile: '',
company: '',
note: '',
})
const customerInfoVisible = ref(false)
const onCustomerInfoSubmit = async () => {
if (!customer.name || !customer.mobile) {
ElMessage({
message: '请填写姓名和手机号',
type: 'warning'
})
return
}
if (!utils.isPhone(customer.mobile)) {
ElMessage({
message: '手机号格式不正确',
type: 'warning'
})
return
}
try {
console.log(customer)
let param: any = {
name: customer.name,
mobile: customer.mobile,
company: customer.company,
source: form.source,
note: customer.note,
}
await aitoolsService.commonApi('记录客户信息', 'take_customer_info', param);
// 统计
trackUserAction(form.source, form.user_id, title.value, '客户留资')
customerInfoVisible.value = false
// 防止重复提交
localStorage.setItem("isSubmitCustomerInfo", 'yes');
// 新开一个浏览器窗口,打开一个链接
openNewWindow();
} catch (error) {
ElMessage({
message: String(error),
type: 'error'
})
}
}
const openNewWindow = () => {
if (form.source === 'pc') {
window.open(form.report_url, '_blank');
} else {
if (form.source === 'wechat') {
ElMessageBox.confirm(
'请先<span style="color: red;">「点击确认」</span>查看完整报告,如需保存报告到手机,再至右上角选择<span style="color: red;">「默认浏览器」</span>打开',
'微信提示',
{
confirmButtonText: '确认',
type: 'info',
center: true,
showClose: false,
showCancelButton: false,
dangerouslyUseHTMLString: true,
closeOnClickModal: false,
closeOnPressEscape: false,
}
).then(() => {
window.location.href = form.report_url;
})
} else {
window.location.href = form.report_url;
}
}
}
const onClickDownloadPDF = () => {
const isSubmitCustomerInfo = localStorage.getItem("isSubmitCustomerInfo");
console.log('isSubmitCustomerInfo =', isSubmitCustomerInfo);
if (isSubmitCustomerInfo === 'yes') {
customerInfoVisible.value = false
// 直接打开链接
openNewWindow();
} else {
customerInfoVisible.value = true
}
}
return {
customer,
customerInfoVisible,
onCustomerInfoSubmit,
onClickDownloadPDF,
}
}
import { ref } from 'vue'
import {
ElMessage,
genFileId,
type UploadInstance,
type UploadProps,
type UploadRawFile,
type UploadFile,
} from 'element-plus'
export const myFileUpload = (FileSizeLimitM: number, form: any, loading: any) => {
// ############ 处理上传文件 begin #############
const upload = ref<UploadInstance>()
const actionUrl = ref(
import.meta.env.MODE === 'production'
? '/file'
: import.meta.env.VITE_APP_BASE_API + '/file'
)
const handleBeforeUpload = async (file: any) => {
const isLimit = file.size / 1024 / 1024 <= FileSizeLimitM
if (!isLimit) {
ElMessage.error('上传文件大小不能超过 '+FileSizeLimitM+'MB!')
return false
}
}
const handleUploadSuccess = (val: Wm.UploadResult, file: UploadFile) => {
// console.log(val)
if (val.code == 0) {
form.file_path = val.data[0].path
console.log('form.file_path =', form.file_path)
form.file_path_domain = val.data[0].url
console.log('form.file_path_domain =', form.file_path_domain)
// console.log('file =', file.name, file.size, file.url)
if (file.name && file.size !== undefined) {
form.file_name = file.name
form.file_size = file.size
}
ElMessage({
message: '上传成功',
type: 'success'
})
} else {
ElMessage({
message: '上传失败:' + val.message,
type: 'error'
})
}
loading.value = false
}
const handleUploadExceed: UploadProps['onExceed'] = (files) => {
// 清除已上传的文件
upload.value!.clearFiles()
// 获取超出限制的第一个文件
const file = files[0] as UploadRawFile
// 给文件分配一个新的唯一标识
file.uid = genFileId()
// 手动触发文件上传
upload.value!.handleStart(file)
// 提交上传
upload.value!.submit()
}
const handleUploadError = (error: Error) => {
ElMessage({
message: String(error.message),
type: 'error'
})
loading.value = false
}
const handleUploadProgress = (event: ProgressEvent, file: UploadFile) => {
file.percentage = Math.round(event.loaded / event.total * 100)
console.log('上传进度:', file.percentage)
file.url = '/video-icon.png'
// 根据进度控制 loading 状态
if (file.percentage <= 100) {
loading.value = true
}
// if (file.percentage == 100) {
// loading.value = false
// }
}
const handleRemoveFile = () => {
// 清除已上传的文件
// upload.value!.clearFiles()
form.file_path = ""
form.file_path_domain = ""
form.file_name = ""
form.file_size = 0
console.log('文件列表移除File, form.file_path =', form.file_path, ', form.file_path_domain =', form.file_path_domain)
}
// ############ 处理上传文件 end #############
return {
loading,
upload,
actionUrl,
handleBeforeUpload,
handleUploadSuccess,
handleUploadExceed,
handleUploadError,
handleUploadProgress,
handleRemoveFile,
}
}
import aitoolsService from '@/api/service/aitoolsService'
import utils from '@/utils/utils'
import {
ElMessage,
ElLoading,
ElMessageBox
} from 'element-plus'
import type { Action } from 'element-plus'
export const onProcessing = (form: any, steps_active: any, process_loading: any, result_loading: any) => {
const fileToClassify = async () => {
if (!form.file_path || form.file_path.length == 0) {
ElMessage({
message: '请先上传文件',
type: 'warning'
})
return
}
// 进入第二页
from_first_to_second();
// 清除结果
form.sample_result = {
root_path: '',
data: [{
dir_name: '',
images: [],
}]
};
// 提交处理请求
try {
let param: any = {
task_id: form.task_id,
file_path: form.file_path,
crop_range: JSON.stringify(form.crop_range),
box_range: JSON.stringify(form.box_range),
output_type: "dir",
classes_select: "",
target_fps: form.target_fps, // 目标帧率
}
process_loading.value = true;
// 发起请求
aitoolsService.commonApi('提交处理', 'gen_sample_from_video', param)
.then((response) => {
// console.log(form)
console.log(`接口返回:${response}`);
form.sample_result = response;
// 设置默认值
form.classes_select = {}
form.classes_select2 = {}
response.data.forEach((item: { dir_name: string; images: string[] }) => {
form.classes_select[item.dir_name] = '0';
form.classes_select2[item.dir_name] = '';
});
process_loading.value = false;
})
.catch((error) => {
ElMessage({
message: error,
type: 'error'
});
// // 重置task_id
// form.task_id = utils.genDateTimeStr();
// console.log('重置 task_id =', form.task_id);
process_loading.value = false;
})
} catch (error: any) {
ElMessage({
message: error,
type: 'error'
});
process_loading.value = false;
}
}
function isAllDataClassified(): boolean {
let is_ok = false;
if (!form.sample_result?.data || !form.classes_select) {
ElMessage({
message: '数据未正确初始化',
type: 'error'
});
}
form.sample_result.data.every((item: { dir_name: string; images: string[] }) => {
if (!form.classes_select.hasOwnProperty(item.dir_name)) {
ElMessage({
message: `请为${item.dir_name}分类`,
type: 'error'
});
} else {
is_ok = true
}
});
return is_ok;
}
const classifyToDownload = async () => {
if (!isAllDataClassified()) {
return
}
// 进入第3页
from_second_to_third();
// 清除结果
form.sample_path = '';
// 提交处理请求
try {
let param: any = {
task_id: form.task_id,
file_path: form.file_path,
crop_range: JSON.stringify(form.crop_range),
box_range: JSON.stringify(form.box_range),
output_type: "zip",
classes_select: JSON.stringify(form.classes_select),
target_fps: form.target_fps, // 目标帧率
}
result_loading.value = true;
// 发起请求
aitoolsService.commonApi('提交处理', 'gen_sample_from_video', param)
.then((response) => {
// console.log(form)
console.log(`接口返回:${response}`);
form.sample_path = response.sample_path;
result_loading.value = false;
})
.catch((error) => {
ElMessage({
message: error,
type: 'error'
});
// // 重置task_id
// form.task_id = utils.genDateTimeStr();
// console.log('重置 task_id =', form.task_id);
result_loading.value = false;
})
} catch (error: any) {
ElMessage({
message: error,
type: 'error'
});
result_loading.value = false;
}
}
const from_first_to_second = () => {
steps_active.value = 1
}
const back_to_first = () => {
steps_active.value = 0;
form.task_id = utils.genDateTimeStr();
console.log('返回首页,task_id =', form.task_id);
}
const from_second_to_third = () => {
steps_active.value = 2;
}
const back_to_second = () => {
steps_active.value = 1;
form.classes_select2 = JSON.parse(JSON.stringify(form.classes_select));
}
function downloadFile(url: string, filename?: string) {
const a = document.createElement('a')
a.href = url
if (filename) {
a.download = filename // 指定下载文件名
}
a.target = '_blank'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
function deleteOneSample(sample_dir: string) {
ElMessageBox.alert(`确认删除 ${sample_dir} 这行样本吗?`, '删除样本', {
// autofocus: false,
confirmButtonText: '删除',
callback: (action: Action) => {
if (action === 'confirm') {
// 删除 form.sample_result.data
const index = form.sample_result.data.findIndex((item: any) => item.dir_name === sample_dir);
form.sample_result.data.splice(index, 1);
// 删除 form.classes_select[sample_dir]
delete form.classes_select[sample_dir];
// 删除 form.classes_select2[sample_dir]
delete form.classes_select2[sample_dir];
ElMessage({
type: 'success',
message: '删除成功'
})
}
},
})
}
return {
downloadFile,
process_loading,
result_loading,
deleteOneSample,
}
}
\ No newline at end of file
.home-container {
width: 100%;
}
.title {
:is(span) {
font-size: 25px;
font-weight: bold;
color: #181818;
}
text-align: center;
margin: 20px 0 0 0;
}
.subtitle {
:is(span) {
font-size: 13px;
color: #181818;
}
text-align: center;
margin: 0 0 20px 0;
}
.progress {
margin: 10px 50px;
text-align: center;
}
.content-container {
margin: 20px;
display: flex;
flex-direction: row; /* 默认横向排列 */
justify-content: center; /* 水平居中 */
/* box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
border-radius: 8px; /* 可选:添加圆角 */
/* background-color: #fff; /* 可选:添加背景色 */
@media (max-width: 768px) { /* 当屏幕宽度小于768px时变为竖向排列 */
flex-direction: column;
}
}
/* 几个页面的公共样式 */
.upload-section {
padding: 20px;
/* 标题 */
.section-title {
font-size: 18px;
font-weight: bold;
color: #181818;
}
/* 描述 */
.section-desc {
font-size: 12px;
}
/* 上传区域 */
.upload-div {
margin: 20px 0;
/* border: 2px dashed #dddfe5; */
border-radius: 4px;
}
/* 已上传文件 */
.uploaded-div {
margin: 20px 0;
padding: 20px 10px;
border-radius: 4px;
border: 1px dashed #dddfe5; /* 添加边框样式 */
.uploaded-file-info {
position: relative;
margin: 0 auto;
>img {
height: 300px;
}
}
}
/* 按钮 */
.button {
display: flex;
flex-direction: column;
align-items: flex-start;
.next {
align-self: flex-end;
}
}
}
<script setup lang="ts">
import utils from '@/utils/utils'
import { onUpdated, onMounted, reactive, ref } from 'vue'
import { detectDeviceType } from './compositions/common'
import { myFileUpload } from './compositions/fileUpload'
import { onProcessing } from './compositions/process'
import {
Check,
Delete,
Edit,
Message,
Search,
Star,
} from '@element-plus/icons-vue'
const title = ref('元芒数字')
const form = reactive({
source: '',
task_id: '',
file_path: '',
file_path_domain: '',
file_name: '',
file_size: 0,
})
const steps_active = ref(0)
const FileSizeLimitM = 5
const file_loading = ref(false)
const my_file_upload = myFileUpload(FileSizeLimitM, form, file_loading)
const upload = my_file_upload.upload
const actionUrl = my_file_upload.actionUrl
onMounted(async () => {
// 检测设备类型
form.source = detectDeviceType();
// 设置页面标题
document.title = title.value;
// 生成task_id
form.task_id = utils.genDateTimeStr();
console.log('页面加载,task_id =', form.task_id);
})
</script>
<template>
<main class="home-container">
<!-- 标题 -->
<div class="title"><el-text>WM Nano Banana</el-text></div>
<div class="subtitle"><el-text>WM Nano Banana</el-text></div>
<!-- 步骤条 -->
<div>
<el-steps :active="steps_active" align-center finish-status="success">
<el-step title="上传图片"/>
<el-step title="显示结果"/>
</el-steps>
</div>
<div class="content-container">
<!-- 文件页 -->
<div class="upload-section" v-if="steps_active === 0">
<div><el-text class="section-title">上传文件</el-text></div>
<!-- <div><el-text class="section-desc">上传文件</el-text></div> -->
<div class="upload-div" v-loading="file_loading" v-if="!form.file_path">
<el-upload
ref="upload"
:show-file-list="false"
:limit="1"
drag
accept=".png,.jpg,.jpeg"
:action="actionUrl"
:on-success="my_file_upload.handleUploadSuccess"
:on-exceed="my_file_upload.handleUploadExceed"
:on-error="my_file_upload.handleUploadError"
:on-remove="my_file_upload.handleRemoveFile"
:before-upload="my_file_upload.handleBeforeUpload"
:on-progress="my_file_upload.handleUploadProgress"
list-type="picture"
>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">拖拽文件到这里 或 <em>浏览文件</em></div>
<div class="el-upload__tip" slot="tip">文件格式 png/jpg, 大小限制{{FileSizeLimitM}}M</div>
</el-upload>
</div>
<div class="uploaded-div" v-if="form.file_path" >
<div class="uploaded-file-info">
<img :src="form.file_path_domain" />
</div>
</div>
<div class="button">
<el-button class="next" color="#181818" size="large" >下载</el-button>
</div>
</div>
</div>
</main>
</template>
<!-- 样式 只在当前页面生效,优先级比组件样式低 -->
<style lang="scss" scoped src="./index.css"></style>
<!-- 全局样式,如果要改组件样式,得在这里改,但为了避免所有组件都改,这里可以设置class层级 -->
<style lang="scss">
.progress-section {
.classifications {
.class-select-1 {
.el-select__wrapper{
background-color: aquamarine;
}
}
.class-select-2 {
.el-select__wrapper{
background-color: rgb(121, 160, 245);
}
}
.class-select-3 {
.el-select__wrapper{
background-color: rgb(164, 139, 246);
}
}
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment