Skip to content

Commit a59cfe7

Browse files
committed
feat: 优化排版
1 parent d7146ac commit a59cfe7

File tree

20 files changed

+612
-77
lines changed

20 files changed

+612
-77
lines changed

auto-imports.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* eslint-disable */
2+
/* prettier-ignore */
3+
// @ts-nocheck
4+
// Generated by unplugin-auto-import
5+
export {}
6+
declare global {
7+
8+
}

components.d.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* eslint-disable */
2+
/* prettier-ignore */
3+
// @ts-nocheck
4+
// Generated by unplugin-vue-components
5+
// Read more: https://github.com/vuejs/core/pull/3399
6+
export {}
7+
8+
declare module 'vue' {
9+
export interface GlobalComponents {
10+
copy: typeof import('./src/components/Image copy.vue')['default']
11+
ElImage: typeof import('element-plus/es')['ElImage']
12+
ElPopover: typeof import('element-plus/es')['ElPopover']
13+
GroupModal: typeof import('./src/components/Group-Modal/index.vue')['default']
14+
Image: typeof import('./src/components/Image.vue')['default']
15+
'Image copy': typeof import('./src/components/Image copy.vue')['default']
16+
Loading: typeof import('./src/components/Loading/index.vue')['default']
17+
LoginModal: typeof import('./src/components/Login-Modal/index.vue')['default']
18+
Modal: typeof import('./src/components/Modal/index.vue')['default']
19+
SettingsModal: typeof import('./src/components/Settings-Modal/index.vue')['default']
20+
Tag: typeof import('./src/components/Tag.vue')['default']
21+
Toast: typeof import('./src/components/Toast/index.vue')['default']
22+
UseModal: typeof import('./src/components/Use-Modal/index.vue')['default']
23+
}
24+
export interface ComponentCustomProperties {
25+
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
26+
}
27+
}

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
"@vueuse/core": "^10.1.2",
1313
"clipboard": "^2.0.11",
1414
"crypto-js": "^4.1.1",
15+
"element-plus": "^2.3.6",
1516
"socket.io-client": "^4.6.2",
16-
"vue": "^3.2.47",
17-
"vue3-lazy": "^1.0.0-alpha.1"
17+
"vue": "^3.2.47"
1818
},
1919
"devDependencies": {
2020
"@types/node": "^20.3.0",
@@ -26,6 +26,8 @@
2626
"postcss": "^8.4.24",
2727
"tailwindcss": "^3.3.2",
2828
"typescript": "^5.0.2",
29+
"unplugin-auto-import": "^0.16.4",
30+
"unplugin-vue-components": "^0.25.1",
2931
"vite": "^4.3.9",
3032
"vue-tsc": "^1.4.2"
3133
}

src/DrawPanel.vue

Lines changed: 79 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
<script setup lang="ts">
2-
import { reactive, ref, onMounted, defineAsyncComponent } from 'vue';
2+
import { reactive, ref, onMounted, createVNode } from 'vue';
33
import { Message, MessageStatus } from './interfaces/message'
44
import MessageItem from './Message.vue'
55
import { getMessagesAPI, createMessageAPI, upscaleMessageAPI } from './api/midjourney'
6-
import { sendMessage, createWebsocket } from './utils/websocket'
7-
import { useDebounceFn } from '@vueuse/core'
6+
import { createWebsocket } from './utils/websocket'
7+
import { useDebounceFn, } from '@vueuse/core'
88
import Toast from './components/Toast/index'
99
import UseModal from './components/Use-Modal/index.vue'
1010
import SettingsModal from './components/Settings-Modal/index.vue'
1111
import { showModal } from './components/Modal';
12-
import { drawStyles, randomPrompt, getJointPrompt, showLoginModal } from './utils/index'
12+
import { drawStyles, randomPrompt, getJointPrompt } from './utils/index'
1313
import { useLimitHook } from '@/hooks/use-limit-hook';
14+
import { userStorage } from '@/utils/storage';
15+
import { useUser } from '@/hooks/use-user'
16+
import GroupModal from '@/components/Group-Modal/index.vue'
1417
18+
19+
const { isLogin, showLoginModal, userLogout } = useUser()
1520
const showUseModal = () => {
1621
showModal(UseModal, {
1722
title: "使用说明"
@@ -20,17 +25,12 @@ const showUseModal = () => {
2025
2126
const showSettingsModal = () => {
2227
showModal(SettingsModal, {
23-
title: "设置"
28+
title: "设置",
29+
closeOnClickModal: true
2430
})
2531
}
32+
2633
createWebsocket({
27-
onMessage(data) {
28-
// console.log('message event: ', event)
29-
console.log('message event: ', data)
30-
},
31-
onOnLine(data) {
32-
console.log('online data: ', data)
33-
},
3434
onTaskUpdate(data: Message) {
3535
console.log('taskupdate data: ', data)
3636
const { id } = data
@@ -46,11 +46,13 @@ const data = reactive({
4646
messages: [],
4747
pageNum: 1,
4848
pageSize: 5,
49+
initLoading: true,
4950
loading: false,
5051
loaded: false,
5152
useModalVisible: false,
5253
styles: [...drawStyles],
53-
currentStyle: ''
54+
currentStyle: '',
55+
onlyCurrentUser: false
5456
})
5557
5658
const findOneAndUpdate = (id: number, msgData: Partial<Message>) => {
@@ -80,15 +82,12 @@ const getList = (params: any) => {
8082
return new Promise((resolve, reject) => {
8183
if (data.loading || data.loaded) return
8284
getMessagesAPI(params).then((resData) => {
83-
// data.messages = resData as any;
84-
// ((resData || [] as any) as []).reverse();
85-
// data.messages = [...resData as any, ...data.messages];
86-
8785
data.messages = data.messages.concat(resData)
8886
8987
data.loaded = !resData || !(resData as any).length
9088
}).finally(() => {
9189
data.loading = false
90+
data.initLoading = false
9291
resolve(undefined)
9392
})
9493
})
@@ -111,6 +110,9 @@ const sendPrompt = async () => {
111110
}, 2000)
112111
return
113112
}
113+
if (data.prompt.length > 500) {
114+
return Toast({ value: "描述过长,最多500个字符,包括标点符号" })
115+
}
114116
const newPmt = getJointPrompt(data.prompt)
115117
const msgId = await createMessageAPI(newPmt) as any;
116118
console.log("msgId: ", msgId)
@@ -121,11 +123,11 @@ const sendPrompt = async () => {
121123
id: msgId,
122124
status: MessageStatus.INIT
123125
}
124-
126+
125127
data.messages.unshift(msgObj)
126128
data.prompt = ''
127129
recordTimeUse()
128-
scrollToBottom()
130+
// scrollToBottom()
129131
}
130132
131133
const onUpscale = async (msg: Message) => {
@@ -155,7 +157,7 @@ const onUpscale = async (msg: Message) => {
155157
const scrollToBottom = () => {
156158
setTimeout(() => {
157159
if (contentWrap.value) {
158-
contentWrap.value.scrollTop = contentWrap.value.scrollHeight
160+
// contentWrap.value.scrollTop = contentWrap.value.scrollHeight
159161
}
160162
})
161163
}
@@ -173,8 +175,42 @@ const helpThink = () => {
173175
data.prompt = p
174176
}
175177
178+
const onlyForMe = () => {
179+
setTimeout(() => {
180+
const user = userStorage.get();
181+
const isForUser = data.onlyCurrentUser
182+
const queries: any = {
183+
pageNum: 1,
184+
pageSize: data.pageSize,
185+
}
186+
if (isForUser) {
187+
if (!user) {
188+
data.onlyCurrentUser = false;
189+
return showLoginModal()
190+
}
191+
if (user && user.username) {
192+
queries.username = user.username
193+
}
194+
}
195+
data.loaded = false
196+
data.initLoading = true;
197+
data.messages = []
198+
data.pageNum = 1
199+
getList(queries)
200+
data.loading = true
201+
})
202+
}
203+
204+
const showGroupModal = () => {
205+
showModal(GroupModal, {
206+
closeOnClickModal: true,
207+
closeOnPressEscape: true
208+
})
209+
}
210+
176211
onMounted(() => {
177212
getList({ pageNum: 1, pageSize: data.pageSize }).finally(() => {
213+
data.initLoading = false
178214
setTimeout(() => {
179215
contentWrap.value.addEventListener('scroll', onContentWrapScroll)
180216
scrollToBottom()
@@ -191,34 +227,37 @@ onMounted(() => {
191227
<template>
192228
<!-- <div class="h-full w-full max-sm:py-0 bg-gray-600" v-loading:[title]="true"> -->
193229
<div class="h-full w-full max-sm:py-0 bg-gray-600">
194-
<div class="relative h-full max-w-[980px] bg-gray-700 m-auto text-white px-10 py-4 sm:py-0 max-sm:py-2 max-sm:px-4 rounded-none">
195-
<div id="contentWrap" ref="contentWrap" class="h-[calc(100%-150px)] overflow-auto m-auto flex flex-col-reverse">
230+
<div
231+
class="relative h-full max-w-[980px] bg-gray-700 m-auto text-white px-10 py-4 sm:py-0 max-sm:py-2 max-sm:px-4 rounded-none">
232+
<div v-loading="data.initLoading" id="contentWrap" ref="contentWrap"
233+
class="h-[calc(100%-150px)] overflow-auto m-auto flex flex-col-reverse">
196234
<div class="border-b-2 border-purple-400" v-for="(item, index) in data.messages" :key="item.id">
197235
<MessageItem :key="item.id" :message="item" @on-upscale="onUpscale" />
198236
</div>
199237
</div>
200-
<div class="absolute left-10 right-10 max-sm:left-2 max-sm:right-2 bottom-4 max-sm:bottom-2 flex-row items-center justify-between px-2 py-2 bg-gray-100 border-gray-400 rounded-[4px]">
238+
<div
239+
class="absolute left-10 right-10 max-sm:left-2 max-sm:right-2 bottom-4 max-sm:bottom-2 flex-row items-center justify-between px-2 py-2 bg-gray-100 border-gray-400 rounded-[4px]">
201240
<!-- 快捷/帮助区域 -->
202-
<div class="flex w-full px-2 pb-2 pt-1 text-md select-none">
203-
<p class="underline text-orange-400 pr-4 cursor-pointer" @click.stop="helpThink">帮我想一个</p>
204-
<p class="underline text-orange-400 pr-4 cursor-pointer" @click.stop="showSettingsModal">设置参数</p>
205-
<p class="underline text-orange-400 pr-4 cursor-pointer" @click.stop="showSettingsModal">设置风格</p>
241+
<div class="flex w-full px-2 pb-2 pt-1 text-md select-none flex-wrap">
242+
<p class="underline text-orange-400 pr-4 cursor-pointer max-sm:text-sm" @click.stop="helpThink">想一个</p>
243+
<p class="underline text-orange-400 pr-4 cursor-pointer max-sm:text-sm" @click.stop="showSettingsModal">设置</p>
244+
<!-- <p class="underline text-orange-400 pr-4 cursor-pointer" @click.stop="showSettingsModal">设置风格</p> -->
245+
<p class="underline text-orange-400 cursor-pointer max-sm:text-sm" @click.stop="showUseModal">使用说明</p>
246+
<p class="underline text-orange-400 pr-4 ml-4 max-sm:text-sm" @click.stop="onlyForMe">
247+
<input id="onlyMe" v-model="data.onlyCurrentUser" type="checkbox" class="cursor-pointer">
248+
<label for="onlyMe" class="cursor-pointer">只看自己</label>
249+
</p>
206250
<p class="flex-1"></p>
207-
<p class="underline text-orange-400 pr-4 cursor-pointer font-bold" @click.stop="showLoginModal">登录/注册</p>
208-
<p class="underline text-orange-400 pr-4 cursor-pointer">微信交流群</p>
209-
<p class="underline text-orange-400 cursor-pointer" @click.stop="showUseModal">使用说明</p>
210-
</div>
251+
<p class="underline text-orange-400 pr-4 cursor-pointer max-sm:text-sm" @click="showGroupModal">交流群</p>
252+
<p v-if="!isLogin" class="underline text-orange-400 pr-4 cursor-pointer font-bold max-sm:text-sm" @click.stop="showLoginModal">登录/注册</p>
253+
<p v-if="isLogin" class="underline text-orange-400 pr-4 cursor-pointer max-sm:text-sm" @click.stop="userLogout">退出</p>
254+
</div>
211255
<!-- 输入框 -->
212256
<div class="w-full bg-white flex items-center">
213-
<textarea
214-
v-model="data.prompt"
215-
class="flex-1 px-4 py-2 resize-none rounded-[8px] outline-none max-sm:text-sm text-md text-gray-500"
216-
autofocus
217-
placeholder="输入图片描述,例如'可爱的橘黄色的猫咪, 迪士尼风格'、'海边,机器人,小女孩,吉卜力风格'等"
218-
type="textarea"
219-
:rows="2"
220-
@keydown.enter.prevent.stop="onKeyDown"
221-
/>
257+
<textarea v-model="data.prompt"
258+
class="flex-1 px-4 py-2 resize-none rounded-[8px] outline-none max-sm:text-sm text-md text-gray-500" autofocus
259+
placeholder="输入图片描述,例如'可爱的橘黄色的猫咪, 迪士尼风格'、'海边,机器人,小女孩,吉卜力风格'等" type="textarea" :rows="2"
260+
@keydown.enter.prevent.stop="onKeyDown" />
222261
<img @click="onClickSend" class="mx-4 w-[36px] h-[36px] cursor-pointer" src="/src/assets/send.png" alt="">
223262
</div>
224263
</div>

src/assets/group.jpg

179 KB
Loading

src/components/Group-Modal/index.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<script setup lang="ts">
2+
const props = defineProps({
3+
close: {
4+
type: Function
5+
}
6+
})
7+
8+
const onClickCancel = () => {
9+
props.close?.()
10+
}
11+
12+
</script>
13+
14+
<template>
15+
<div class="">
16+
<img src="/src/assets/group.jpg" alt="">
17+
</div>
18+
</template>

src/components/Image copy.vue

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<script setup lang="ts">
2+
import { computed, reactive } from 'vue';
3+
4+
const props = defineProps({
5+
url: {
6+
type: String,
7+
default: ""
8+
},
9+
width: {
10+
type: [String, Number],
11+
default: '100%'
12+
},
13+
loadText: {
14+
type: String,
15+
default: "加载中"
16+
},
17+
errorText: String,
18+
})
19+
20+
const cdnHost = 'cdn.discordapp.com'
21+
const cdnHost2 = 'midjourney.cdn.zhishuyun.com'
22+
const trueUrl = computed(() => {
23+
if (props.url && props.url.indexOf(cdnHost) !== -1) {
24+
return props.url.replace(cdnHost, cdnHost2)
25+
}
26+
return props.url
27+
})
28+
29+
const data = reactive({
30+
loading: false,
31+
loaded: false,
32+
loadError: false
33+
})
34+
35+
const onLoadStart = (event: Event) => {
36+
console.log('load start: ', event)
37+
data.loading = true
38+
}
39+
const onLoadError = (event: Event) => {
40+
console.log('load eroor: ', event)
41+
data.loadError = true
42+
}
43+
const onLoad = () => {
44+
data.loading = false
45+
data.loaded = true
46+
}
47+
</script>
48+
49+
<template>
50+
<div class="relative w-full bg-gray-500 rounded my-2 h-0 pb-[100%]">
51+
<img v-if="trueUrl" v-lazy="trueUrl" class="absolute top-0 left-0 w-[100%] h-[100%] object-contain" loading="lazy" alt="" @loadstart="onLoadStart" @error="onLoadError" @load="onLoad">
52+
</div>
53+
</template>

src/components/Image.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@ const onLoad = () => {
4848

4949
<template>
5050
<div class="relative w-full bg-gray-500 rounded my-2 h-0 pb-[100%]">
51-
<img v-if="trueUrl" v-lazy="trueUrl" class="absolute top-0 left-0 w-[100%] h-[100%] object-contain" loading="lazy" alt="" @loadstart="onLoadStart" @error="onLoadError" @load="onLoad">
51+
<el-image style="position: absolute !important;" class="absolute w-[100%] h-[100%] object-contain" v-if="trueUrl"
52+
fit="contain" :src="trueUrl" lazy :preview-src-list="[trueUrl]" hide-on-click-modal>
53+
<template #placeholder>
54+
<div class="w-full h-full" v-loading="true" element-loading-text="正在加载图片"></div>
55+
</template>
56+
<template #error>
57+
<div class="w-full h-full flex items-center justify-center" v-loading="false" element-loading-text="加载失败">加载失败</div>
58+
</template>
59+
</el-image>
60+
<!-- <img v-if="trueUrl" v-lazy="trueUrl" class="absolute top-0 left-0 w-[100%] h-[100%] object-contain" loading="lazy" alt="" @loadstart="onLoadStart" @error="onLoadError" @load="onLoad"> -->
5261
</div>
5362
</template>

src/components/Login-Modal/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ const onClickCancel = () => {
8888
</script>
8989

9090
<template>
91-
<div class="max-w-[600px] px-8 py-4 min-w-[420px]" v-loading="form.loading">
91+
<div class="max-w-[600px] px-8 py-4 min-w-[420px]" todayUsed="form.loading">
9292
<img class="block m-auto pb-4" src="/src/assets/coffee.png" alt="">
9393
<p class="py-1 pb-4 text-center text-orange-100 font-bold">欢迎使用</p>
9494
<div class="flex justify-between items-center py-2 text-sm mb-2" >

src/components/Modal/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ interface IShowModal {
66
visible?: boolean;
77
showClose?: boolean;
88
onClose?: () => void;
9+
closeOnClickModal?: boolean;
10+
closeOnPressEscape?: boolean
911
}
1012
export const showModal = (component: VNodeTypes, props: IShowModal = {}) => {
1113
return new Promise((resolve, reject) => {
@@ -15,6 +17,8 @@ export const showModal = (component: VNodeTypes, props: IShowModal = {}) => {
1517
title: props.title,
1618
modelValue: true,
1719
showClose: props.showClose,
20+
closeOnClickModal: props.closeOnClickModal || false,
21+
closeOnPressEscape: props.closeOnPressEscape || false,
1822
onClose: () => {
1923
document.body.removeChild(container)
2024
props?.onClose?.()

0 commit comments

Comments
 (0)