refactor: migrate from Vue CLI to Vite, update WebSocket handling, and clean up configuration

- Replaced vue.config.js with vite.config.js for Vite setup.
- Updated WebSocket implementation in webSocket.js for improved readability and performance.
- Removed unnecessary comments and cleaned up code formatting.
- Configured Vite plugins for auto-imports, SVG icons, and component resolution.
- Set up proxy configurations for API endpoints in Vite.
This commit is contained in:
bighuixiang
2025-06-18 14:31:35 +08:00
parent 9191678708
commit 3a52cc1e53
19 changed files with 20706 additions and 26139 deletions

View File

@@ -306,7 +306,7 @@ export class BatchInitializeRedGreenModeCommand extends Command {
*/
async _setupBackgroundLayer(backgroundLayer, clothingImage) {
let backgroundObject = backgroundLayer.fabricObject;
const { object } = findObjectById(this.canvas, backgroundObject.id);
let { object } = findObjectById(this.canvas, backgroundObject.id);
if (!object) {
// 创建白色背景矩形

File diff suppressed because it is too large Load Diff

View File

@@ -1,459 +1,530 @@
<template>
<div class="newProject">
<div class="contentBox">
<div class="content">
<div class="title">How can I help you today?</div>
<div class="selectFlow">
<div class="select">
<div class="item" @click="setFlow(item)" :class="{active:item.title == selectFlow.title}" v-for="item in flowList">{{ item.title }}</div>
</div>
<div class="describe">
<p v-for="item in selectFlow.describe">{{ item }}</p>
</div>
</div>
<div class="chatOrSetting">
<div class="select">
<div class="item" @click="setChatOrSetting('chat')" :class="{active:chatOrSetting == 'chat'}">Chat</div>
<div class="item" @click="setChatOrSetting('setting')" :class="{active:chatOrSetting == 'setting'}">Setting</div>
</div>
</div>
<div class="chatBox" v-show="chatOrSetting == 'chat'">
<textarea ref="textarea" @input="inputText($event)" @keydown.enter.prevent="sendChat" placeholder="Write your message"></textarea>
<div class="btn">
<div class="uploadBox">
<div class="filList">
<div class="item" v-for="item,index in filList">
<div>{{item.name}}</div>
<span class="icon iconfont icon-shanchu" @click="deleteFile(item,index)"></span>
</div>
</div>
<i class="fi fi-rs-paperclip-vertical">
<input type="file" @change="handleFileUpload($event)">
</i>
<div class="enableThinking" :class="{active:enableThinking}" @click="()=>enableThinking = !enableThinking">Deep Thinking</div>
</div>
<div class="sendBox">
<div class="maxNum">{{ chatContent.length }}/10000</div>
<div class="send" @click="sendChat">
<i class="fi fi-ss-paper-plane-top"></i>
</div>
</div>
</div>
</div>
<div v-show="chatOrSetting != 'chat'" class="workspaceBox">
<workspace @setProject="setProject" :httpWorkflowType="selectFlow.value"></workspace>
</div>
<div class="hint" v-show="chatOrSetting == 'chat'">
<div class="item" v-for="item in hintList" @click="addChatContent(item)">{{ item }}</div>
</div>
</div>
</div>
<div class="mark_loading" v-show="loadingShow">
<a-spin size="large" />
</div>
</div>
<div class="newProject">
<div class="contentBox">
<div class="content">
<div class="title">How can I help you today?</div>
<div class="selectFlow">
<div class="select">
<div
class="item"
@click="setFlow(item)"
:class="{ active: item.title == selectFlow.title }"
v-for="item in flowList"
>
{{ item.title }}
</div>
</div>
<div class="describe">
<p v-for="item in selectFlow.describe">{{ item }}</p>
</div>
</div>
<div class="chatOrSetting">
<div class="select">
<div
class="item"
@click="setChatOrSetting('chat')"
:class="{ active: chatOrSetting == 'chat' }"
>
Chat
</div>
<div
class="item"
@click="setChatOrSetting('setting')"
:class="{ active: chatOrSetting == 'setting' }"
>
Setting
</div>
</div>
</div>
<div class="chatBox" v-show="chatOrSetting == 'chat'">
<textarea
ref="textarea"
@input="inputText($event)"
@keydown.enter.prevent="sendChat"
placeholder="Write your message"
></textarea>
<div class="btn">
<div class="uploadBox">
<div class="filList">
<div class="item" v-for="(item, index) in filList">
<div>{{ item.name }}</div>
<span
class="icon iconfont icon-shanchu"
@click="deleteFile(item, index)"
></span>
</div>
</div>
<i class="fi fi-rs-paperclip-vertical">
<input type="file" @change="handleFileUpload($event)" />
</i>
<div
class="enableThinking"
:class="{ active: enableThinking }"
@click="() => (enableThinking = !enableThinking)"
>
Deep Thinking
</div>
</div>
<div class="sendBox">
<div class="maxNum">{{ chatContent.length }}/10000</div>
<div class="send" @click="sendChat">
<i class="fi fi-ss-paper-plane-top"></i>
</div>
</div>
</div>
</div>
<div v-show="chatOrSetting != 'chat'" class="workspaceBox">
<workspace
@setProject="setProject"
:httpWorkflowType="selectFlow.value"
></workspace>
</div>
<div class="hint" v-show="chatOrSetting == 'chat'">
<div
class="item"
v-for="item in hintList"
@click="addChatContent(item)"
>
{{ item }}
</div>
</div>
</div>
</div>
<div class="mark_loading" v-show="loadingShow">
<a-spin size="large" />
</div>
</div>
</template>
<script lang="ts">
import { defineComponent,computed,ref,provide,nextTick,createVNode,toRefs, reactive, onMounted} from 'vue'
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import {
defineComponent,
computed,
ref,
provide,
nextTick,
createVNode,
toRefs,
reactive,
onMounted,
} from "vue";
import { ExclamationCircleOutlined } from "@ant-design/icons-vue";
import { Https } from "@/tool/https";
import { useStore } from "vuex";
import { Modal,message,Upload,CascaderProps } from 'ant-design-vue';
import { useI18n } from 'vue-i18n'
import {getCookie,clonAllCookie} from '@/tool/cookie'
import router from '@/router';
import workspace from './workspace.vue'
import { Modal, message, Upload, CascaderProps } from "ant-design-vue";
import { useI18n } from "vue-i18n";
import { getCookie, clonAllCookie } from "@/tool/cookie";
import router from "@/router";
import workspace from "./workspace.vue";
export default defineComponent({
components:{
workspace,
},
props:{
},
emits:['newProject'],
setup(props,{emit}) {
const store = useStore();
const data = reactive({
flowList:[
{
title:'Series Design',
value:'SERIES_DESIGN',
describe:[
'Series Design focuses on the coordinated design of multi-category clothing, ideal for creating a unified fashion collection. You can use the Moodboard, Printboard, Colorboard, Sketchboard, and Mannequin sections in the Design Assests panel to organize your inspiration and design complementary clothing combinations. Finally, refine your designs in the Draft and Collection panels using tools like To Product Image, Relight, and Transfer Pose, then export to the Canvas to showcase your complete series design.',
]
},
{
title:'Single Design',
value:'SINGLE_DESIGN',
describe:[
'Single Design centers on the independent design of a single clothing category, such as a T-shirt, dress, or jacket, without considering coordination with other items. Use the Moodboard, Printboard, Colorboard, and Sketchboard in the Design Assests panel to gather inspiration and focus on crafting a unique piece. Once completed, optimize your design in the Draft and Collection panels with tools like To Product Image, Relight, and Transfer Pose, then export to the Canvas to display your individual creation.',
]
},
],
selectFlow:{
title:'Series Design',
value:'SERIES_DESIGN',
describe:[
'Series Design focuses on the coordinated design of multi-category clothing, ideal for creating a unified fashion collection. You can use the Moodboard, Printboard, Colorboard, Sketchboard, and Mannequin sections in the Design Assests panel to organize your inspiration and design complementary clothing combinations. Finally, refine your designs in the Draft and Collection panels using tools like To Product Image, Relight, and Transfer Pose, then export to the Canvas to showcase your complete series design.',
]
},
chatContent:'',
hintList:[
'设计一套田园风衣服',
'设计一套夏日风衣服',
'设计一套未来风格的衣服',
],
enableThinking:false,//深度思考
uploadFile:null as any,
loadingShow:false,
text:'',
filList:[] as any,
textarea:null as any,
chatOrSetting:'chat',
})
const dataDom = reactive({
})
const setFlow = (item:any)=>{
data.selectFlow = item
}
const inputText = (e:any)=>{
if(e.target.value.length <= 1000){
data.chatContent = e.target.value
}else{
e.target.value = data.chatContent
}
e.target.style.height = `${e.target.scrollHeight}px`;
}
const addChatContent = (item:any)=>{
if((data.textarea.value?.length + item.length) > 10000)return
data.chatContent += item
data.textarea.value += item
}
const sendChat = ()=>{
if(!data.chatContent)return
data.loadingShow = true
let fileList = JSON.parse(JSON.stringify(data.filList))
let fileUrl = (fileList.filter((item:any)=>item.type == 'file').length > 0) ? fileList.filter((item:any)=>item.type == 'file')[0].minioPath : ''
let imageUrlList = (fileList.filter((item:any)=>item.type == 'image').length > 0)? fileList.filter((item:any)=>item.type == 'image').map((item:any)=>item.minioPath).join(',') : ''
Https.axiosGet(Https.httpUrls.chatCreateProject, {params:{prompt:data.chatContent,process:data.selectFlow.value,fileUrl:fileUrl,imageUrlList}}).then((rv)=>{
if(rv){
data.loadingShow = false
let value = {
id:rv,
fileList:fileList,
chatContent:data.chatContent,
enableThinking:data.enableThinking,
}
emit('newProject',value)
}
}).catch(()=>{
data.loadingShow = false
})
// let projectId = ''
// const eventSource = new EventSource(`${process.env.VUE_APP_BASE_URL}${Https.httpUrls.llmStream}?token=${getCookie('token')}&prompt=${data.chatContent}&projectId=&fileUrl=${fileUrl}&imageUrlList=${imageUrlList}&enableThinking=${data.enableThinking}&process=${data.selectFlow.value}`);
// eventSource.onmessage = function(event) {
// let eventData = JSON.parse(event.data)
// if(eventData.status == "[PROJECT_CREATE_SIGNAL]"){
// projectId = JSON.parse(eventData.tools_data).projectId
// }
// };
// eventSource.onerror = function(error) {
// if (eventSource.readyState === EventSource.CLOSED) {
// // data.chatList[data.chatList.length-1].content.message='服务器繁忙,请稍后再试。'
// } else {
// if(projectId){
// emit('newProject',projectId)
// }
// eventSource.close()
// }
// data.loadingShow = false
// };
}
const handleFileUpload = (event:any)=>{
if (event.target.files[0].size > 5 * 1024 * 1024) { // 5MB
message.info('The file size cannot exceed 5MB.');
return
}
let type = event.target.files[0].type.startsWith('image/')
if(type){
if(data.filList.filter((item:any)=>item.type == 'image').length >= 5){
message.info('You can only upload five pictures.');
return
}
}else{
if(data.filList.filter((item:any)=>item.type == 'file').length >= 1){
message.info('You can only upload one file.');
return
}
}
data.loadingShow = true
const formData = new FormData();
formData.append('file', event.target.files[0]);
let config:any = {
headers:{'Content-Type':'multipart/form-data','Accept':'*/*' },
params:formData,
}
Https.axiosPost(Https.httpUrls.llmUploadFile,formData,config)
.then((rv: any) => {
let obj = {
name:event.target.files[0].name,
type:type?'image':'file',
minioPath:rv[0],
url:rv[1],
}
data.filList.push(obj)
data.loadingShow = false
}
).catch(rv=>{
data.loadingShow = false
})
}
const deleteFile = (item:any,index:number)=>{
data.filList.splice(index,1)
}
const setChatOrSetting = (str:any)=>{
data.chatOrSetting = str
}
const setProject = (item:any)=>{
router.push(`home?history=${item.id}`)
}
onMounted(()=>{
store.commit('createProbject')
})
return{
...toRefs(dataDom),
...toRefs(data),
setFlow,
inputText,
addChatContent,
sendChat,
handleFileUpload,
deleteFile,
setChatOrSetting,
setProject,
}
},
provide() {
return {
}
},
})
components: {
workspace,
},
props: {},
emits: ["newProject"],
setup(props, { emit }) {
const store = useStore();
const data = reactive({
flowList: [
{
title: "Series Design",
value: "SERIES_DESIGN",
describe: [
"Series Design focuses on the coordinated design of multi-category clothing, ideal for creating a unified fashion collection. You can use the Moodboard, Printboard, Colorboard, Sketchboard, and Mannequin sections in the Design Assests panel to organize your inspiration and design complementary clothing combinations. Finally, refine your designs in the Draft and Collection panels using tools like To Product Image, Relight, and Transfer Pose, then export to the Canvas to showcase your complete series design.",
],
},
{
title: "Single Design",
value: "SINGLE_DESIGN",
describe: [
"Single Design centers on the independent design of a single clothing category, such as a T-shirt, dress, or jacket, without considering coordination with other items. Use the Moodboard, Printboard, Colorboard, and Sketchboard in the Design Assests panel to gather inspiration and focus on crafting a unique piece. Once completed, optimize your design in the Draft and Collection panels with tools like To Product Image, Relight, and Transfer Pose, then export to the Canvas to display your individual creation.",
],
},
],
selectFlow: {
title: "Series Design",
value: "SERIES_DESIGN",
describe: [
"Series Design focuses on the coordinated design of multi-category clothing, ideal for creating a unified fashion collection. You can use the Moodboard, Printboard, Colorboard, Sketchboard, and Mannequin sections in the Design Assests panel to organize your inspiration and design complementary clothing combinations. Finally, refine your designs in the Draft and Collection panels using tools like To Product Image, Relight, and Transfer Pose, then export to the Canvas to showcase your complete series design.",
],
},
chatContent: "",
hintList: [
"设计一套田园风衣服",
"设计一套夏日风衣服",
"设计一套未来风格的衣服",
],
enableThinking: false, //深度思考
uploadFile: null as any,
loadingShow: false,
text: "",
filList: [] as any,
textarea: null as any,
chatOrSetting: "chat",
});
const dataDom = reactive({});
const setFlow = (item: any) => {
data.selectFlow = item;
};
const inputText = (e: any) => {
if (e.target.value.length <= 1000) {
data.chatContent = e.target.value;
} else {
e.target.value = data.chatContent;
}
e.target.style.height = `${e.target.scrollHeight}px`;
};
const addChatContent = (item: any) => {
if (data.textarea.value?.length + item.length > 10000) return;
data.chatContent += item;
data.textarea.value += item;
};
const sendChat = () => {
if (!data.chatContent) return;
data.loadingShow = true;
let fileList = JSON.parse(JSON.stringify(data.filList));
let fileUrl =
fileList.filter((item: any) => item.type == "file").length > 0
? fileList.filter((item: any) => item.type == "file")[0].minioPath
: "";
let imageUrlList =
fileList.filter((item: any) => item.type == "image").length > 0
? fileList
.filter((item: any) => item.type == "image")
.map((item: any) => item.minioPath)
.join(",")
: "";
Https.axiosGet(Https.httpUrls.chatCreateProject, {
params: {
prompt: data.chatContent,
process: data.selectFlow.value,
fileUrl: fileUrl,
imageUrlList,
},
})
.then((rv) => {
if (rv) {
data.loadingShow = false;
let value = {
id: rv,
fileList: fileList,
chatContent: data.chatContent,
enableThinking: data.enableThinking,
};
emit("newProject", value);
}
})
.catch(() => {
data.loadingShow = false;
});
// let projectId = ''
// const eventSource = new EventSource(`${import.meta.env.VITE_APP_BASE_URL}${Https.httpUrls.llmStream}?token=${getCookie('token')}&prompt=${data.chatContent}&projectId=&fileUrl=${fileUrl}&imageUrlList=${imageUrlList}&enableThinking=${data.enableThinking}&process=${data.selectFlow.value}`);
// eventSource.onmessage = function(event) {
// let eventData = JSON.parse(event.data)
// if(eventData.status == "[PROJECT_CREATE_SIGNAL]"){
// projectId = JSON.parse(eventData.tools_data).projectId
// }
// };
// eventSource.onerror = function(error) {
// if (eventSource.readyState === EventSource.CLOSED) {
// // data.chatList[data.chatList.length-1].content.message='服务器繁忙,请稍后再试。'
// } else {
// if(projectId){
// emit('newProject',projectId)
// }
// eventSource.close()
// }
// data.loadingShow = false
// };
};
const handleFileUpload = (event: any) => {
if (event.target.files[0].size > 5 * 1024 * 1024) {
// 5MB
message.info("The file size cannot exceed 5MB.");
return;
}
let type = event.target.files[0].type.startsWith("image/");
if (type) {
if (
data.filList.filter((item: any) => item.type == "image").length >= 5
) {
message.info("You can only upload five pictures.");
return;
}
} else {
if (
data.filList.filter((item: any) => item.type == "file").length >= 1
) {
message.info("You can only upload one file.");
return;
}
}
data.loadingShow = true;
const formData = new FormData();
formData.append("file", event.target.files[0]);
let config: any = {
headers: { "Content-Type": "multipart/form-data", Accept: "*/*" },
params: formData,
};
Https.axiosPost(Https.httpUrls.llmUploadFile, formData, config)
.then((rv: any) => {
let obj = {
name: event.target.files[0].name,
type: type ? "image" : "file",
minioPath: rv[0],
url: rv[1],
};
data.filList.push(obj);
data.loadingShow = false;
})
.catch((rv) => {
data.loadingShow = false;
});
};
const deleteFile = (item: any, index: number) => {
data.filList.splice(index, 1);
};
const setChatOrSetting = (str: any) => {
data.chatOrSetting = str;
};
const setProject = (item: any) => {
router.push(`home?history=${item.id}`);
};
onMounted(() => {
store.commit("createProbject");
});
return {
...toRefs(dataDom),
...toRefs(data),
setFlow,
inputText,
addChatContent,
sendChat,
handleFileUpload,
deleteFile,
setChatOrSetting,
setProject,
};
},
provide() {
return {};
},
});
</script>
<style lang="less" scoped>
.newProject{
width: 100%;
height: 100%;
position: relative;
> .contentBox{
width: 100%;
height: calc(100% - 3.9rem);
// height: calc(100% - 7.8rem);
display: flex;
align-items: center;
justify-content: center;
> .content{
// background: red;
width: 88rem;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
> .title{
font-size: 2rem;
font-weight: 600;
text-align: center;
}
> .workspaceBox{
flex: 1;
border-radius: 2.4rem;
padding: 1.2rem;
border: 1px solid #0000001a;
:deep(.workspace){
padding: 0;
height: auto;
}
}
> .selectFlow{
margin-top: 4.8rem;
width: 100%;
border-radius: 2.4rem;
border: 1px solid #0000001a;
padding: 1.2rem;
> .select{
border: 1px solid #0000001a;
border-radius: 2.4rem;
display: flex;
padding: .2rem;
border-radius: 2rem;
> div{
white-space: nowrap;
justify-content: space-between;
border-radius: 2.2rem;
font-size: 1.6rem;
padding: .6rem .8rem;
min-width: 25%;
text-align: center;
font-weight: 600;
color: #71717a;
cursor: pointer;
&.active{
background: #efeff1;
color: #3f3f46;
}
}
}
> .describe{
margin-top: 1.6rem;
margin-left: .8rem;
> p{
margin: 0;
color: #71717a;
font-weight: 400;
font-size: 1.2rem;
}
}
}
> .chatOrSetting{
margin-top: 2.4rem;
width: min-content;
margin-left: auto;
> .select{
border: 1px solid #0000001a;
border-radius: 2.4rem;
display: flex;
padding: .2rem;
border-radius: 2rem;
> div{
white-space: nowrap;
justify-content: space-between;
border-radius: 2.2rem;
font-size: 1.6rem;
padding: .6rem .8rem;
min-width: 10rem;
text-align: center;
font-weight: 600;
color: #71717a;
cursor: pointer;
&.active{
background: #efeff1;
color: #3f3f46;
}
}
}
}
> .chatBox{
margin-top: .4rem;
border-radius: 2.4rem;
position: relative;
background: #f5f5f5;
> textarea{
padding: 1.6rem 2rem 0;
background: #f5f5f5;
width: 100%;
min-height: 7.2rem;
border-radius: 2.4rem;
font-weight: 400;
line-height: 2rem;
font-size: 1.4rem;
resize: none;
border: none;
overflow-y: hidden;
}
> .btn{
padding: 0 1.2rem 1.2rem;
display: flex;
justify-content: space-between;
> .uploadBox{
display: flex;
align-items: center;
> .filList{
display: flex;
> .item{
height: 3rem;
padding: .5rem 1rem;
background: #efeff1;
border-radius: .5rem;
margin-right: 1rem;
font-size: 1.4rem;
line-height: 2rem;
display: flex;
> div{
white-space: nowrap;
overflow: hidden;
max-width: 10rem;
text-overflow: ellipsis;
}
> span{
cursor: pointer;
}
}
}
> .enableThinking{
width: 10rem;
padding: .2rem .4rem;
margin-left: 1rem;
text-align: center;
font-size: 1.4rem;
border: 1px solid #000;
border-radius: .4rem;
cursor: pointer;
&.active{
background: #000;
color: #fff;
.newProject {
width: 100%;
height: 100%;
position: relative;
> .contentBox {
width: 100%;
height: calc(100% - 3.9rem);
// height: calc(100% - 7.8rem);
display: flex;
align-items: center;
justify-content: center;
> .content {
// background: red;
width: 88rem;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
> .title {
font-size: 2rem;
font-weight: 600;
text-align: center;
}
> .workspaceBox {
flex: 1;
border-radius: 2.4rem;
padding: 1.2rem;
border: 1px solid #0000001a;
:deep(.workspace) {
padding: 0;
height: auto;
}
}
> .selectFlow {
margin-top: 4.8rem;
width: 100%;
border-radius: 2.4rem;
border: 1px solid #0000001a;
padding: 1.2rem;
> .select {
border: 1px solid #0000001a;
border-radius: 2.4rem;
display: flex;
padding: 0.2rem;
border-radius: 2rem;
> div {
white-space: nowrap;
justify-content: space-between;
border-radius: 2.2rem;
font-size: 1.6rem;
padding: 0.6rem 0.8rem;
min-width: 25%;
text-align: center;
font-weight: 600;
color: #71717a;
cursor: pointer;
&.active {
background: #efeff1;
color: #3f3f46;
}
}
}
> .describe {
margin-top: 1.6rem;
margin-left: 0.8rem;
> p {
margin: 0;
color: #71717a;
font-weight: 400;
font-size: 1.2rem;
}
}
}
> .chatOrSetting {
margin-top: 2.4rem;
width: min-content;
margin-left: auto;
> .select {
border: 1px solid #0000001a;
border-radius: 2.4rem;
display: flex;
padding: 0.2rem;
border-radius: 2rem;
> div {
white-space: nowrap;
justify-content: space-between;
border-radius: 2.2rem;
font-size: 1.6rem;
padding: 0.6rem 0.8rem;
min-width: 10rem;
text-align: center;
font-weight: 600;
color: #71717a;
cursor: pointer;
&.active {
background: #efeff1;
color: #3f3f46;
}
}
}
}
> .chatBox {
margin-top: 0.4rem;
border-radius: 2.4rem;
position: relative;
background: #f5f5f5;
> textarea {
padding: 1.6rem 2rem 0;
background: #f5f5f5;
width: 100%;
min-height: 7.2rem;
border-radius: 2.4rem;
font-weight: 400;
line-height: 2rem;
font-size: 1.4rem;
resize: none;
border: none;
overflow-y: hidden;
}
> .btn {
padding: 0 1.2rem 1.2rem;
display: flex;
justify-content: space-between;
> .uploadBox {
display: flex;
align-items: center;
> .filList {
display: flex;
> .item {
height: 3rem;
padding: 0.5rem 1rem;
background: #efeff1;
border-radius: 0.5rem;
margin-right: 1rem;
font-size: 1.4rem;
line-height: 2rem;
display: flex;
> div {
white-space: nowrap;
overflow: hidden;
max-width: 10rem;
text-overflow: ellipsis;
}
> span {
cursor: pointer;
}
}
}
> .enableThinking {
width: 10rem;
padding: 0.2rem 0.4rem;
margin-left: 1rem;
text-align: center;
font-size: 1.4rem;
border: 1px solid #000;
border-radius: 0.4rem;
cursor: pointer;
&.active {
background: #000;
color: #fff;
}
}
}
i {
font-size: 2rem;
display: flex;
cursor: pointer;
position: relative;
> input {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
cursor: pointer;
&::-webkit-file-upload-button {
cursor: pointer;
}
}
}
> .sendBox {
display: flex;
align-items: center;
}
}
}
i{
font-size: 2rem;
display: flex;
cursor: pointer;
position: relative;
> input{
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
cursor: pointer;
&::-webkit-file-upload-button {
cursor: pointer;
}
}
}
> .sendBox{
display: flex;
align-items: center;
> .maxNum{
font-size: 1.2rem;
margin-right: .8rem;
font-weight: 400;
}
}
}
}
> .hint{
display: flex;
margin-top: 2.4rem;
> div{
background: #efeff1;
width: 25rem;
height: 4.8rem;
margin-right: 1.2rem;
border-radius: 1.6rem;
cursor: pointer;
padding: 1.2rem;
&:hover{
background: #f5f5f5;
}
:first-child{
margin-right: 0;
}
}
}
}
}
}
</style>
> .maxNum {
font-size: 1.2rem;
margin-right: 0.8rem;
font-weight: 400;
}
}
}
}
> .hint {
display: flex;
margin-top: 2.4rem;
> div {
background: #efeff1;
width: 25rem;
height: 4.8rem;
margin-right: 1.2rem;
border-radius: 1.6rem;
cursor: pointer;
padding: 1.2rem;
&:hover {
background: #f5f5f5;
}
:first-child {
margin-right: 0;
}
}
}
}
}
}
</style>